WordPress.org

Making WordPress.org

Changeset 2501


Ignore:
Timestamp:
02/15/2016 06:28:02 AM (4 years ago)
Author:
obenland
Message:

W.org Plugins: Code reformatting.

  • Splitting out classes in their own files.
  • Let the automated code formatter run over the plugin.

It should break too many things.

See #1584.

Location:
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory
Files:
3 added
4 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/plugin-directory.php

    r2499 r2501  
    11<?php
    2 /*
    3  * Plugin Name: Plugin Repository
     2/**
     3 * Plugin Name: Plugin Directory
    44 * Plugin URI: http://wordpress.org/plugins/
    55 * Description: Transforms a WordPress site in The Official Plugin Directory.
    66 * Version: 0.1
    7  * Author: wordpressdotorg
    8  * Author URI: http://wordpress.org/
     7 * Author: the WordPress team
     8 * Author URI: https://wordpress.org/
    99 * Text Domain: wporg-plugins
    1010 * License: GPLv2
    1111 * License URI: http://opensource.org/licenses/gpl-2.0.php
     12 *
     13 * @package WPorg_Plugin_Directory
    1214 */
    1315
    14 class Plugin_Directory {
     16include_once( 'class-wporg-plugin-directory.php' );
     17include_once( 'class-wporg-plugin-directory-template.php' );
     18include_once( 'class-wporg-plugin-directory-tools.php' );
    1519
    16     function __construct() {
    17         register_activation_hook( __FILE__, array( $this, 'activate' ) );
    18         register_deactivation_hook( __FILE__, array( $this, 'deactivate' ) );
    19 
    20         add_action( 'init', array( $this, 'init' ) );
    21         add_filter( 'post_type_link', array( $this, 'package_link' ), 10, 2 );
    22         add_filter( 'pre_insert_term', array( $this, 'pre_insert_term_prevent' ) );
    23         add_action( 'pre_get_posts', array( $this, 'use_plugins_in_query' ) );
    24         add_filter( 'the_content', array( $this, 'filter_post_content_to_correct_page' ), 1 );
    25     }
    26 
    27     function activate() {
    28         global $wp_rewrite;
    29 
    30         // Setup the environment
    31         $this->init();
    32 
    33         // %postname% is required
    34         $wp_rewrite->set_permalink_structure( '/%postname%/' );
    35 
    36         // /tags/%slug% is required for tags
    37         $wp_rewrite->set_tag_base( '/tags' );
    38 
    39         // We require the WordPress.org Ratings plugin also be active
    40         if ( ! is_plugin_active( 'wporg-ratings/wporg-ratings.php' ) ) {
    41             activate_plugin( 'wporg-ratings/wporg-ratings.php' );
    42         }
    43    
    44         // Enable the WordPress.org Theme Repo Theme
    45         foreach ( wp_get_themes() as $theme ) {
    46             if ( $theme->get( 'Name' ) === 'WordPress.org Plugins' ) {
    47                 switch_theme( $theme->get_stylesheet() );
    48                 break;
    49             }
    50         }
    51    
    52         flush_rewrite_rules();
    53    
    54         do_action( 'wporg_plugins_activation' );
    55     }
    56 
    57     function deactivate() {
    58         flush_rewrite_rules();
    59    
    60         do_action( 'wporg_plugins_deactivation' );
    61     }
    62 
    63 
    64     function init() {
    65         load_plugin_textdomain( 'wporg-plugins' );
    66 
    67         register_post_type( 'plugin', array(
    68             'labels'      => array(
    69                 'name'               => __( 'Plugins', 'wporg-plugins' ),
    70                 'singular_name'      => __( 'Plugin', 'wporg-plugins' ),
    71                 'add_new'            => __( 'Add New', 'wporg-plugins' ),
    72                 'add_new_item'       => __( 'Add New Plugin', 'wporg-plugins' ),
    73                 'edit_item'          => __( 'Edit Plugin', 'wporg-plugins' ),
    74                 'new_item'           => __( 'New Plugin', 'wporg-plugins' ),
    75                 'view_item'          => __( 'View Plugin', 'wporg-plugins' ),
    76                 'search_items'       => __( 'Search Plugins', 'wporg-plugins' ),
    77                 'not_found'          => __( 'No plugins found', 'wporg-plugins' ),
    78                 'not_found_in_trash' => __( 'No plugins found in Trash', 'wporg-plugins' ),
    79                 'menu_name'          => __( 'My Plugins', 'wporg-plugins' ),
    80             ),
    81             'description' => __( 'A package', 'wporg-plugins' ),
    82             'supports'    => array( 'title', 'editor', 'excerpt', 'custom-fields' ),
    83             'taxonomies'  => array( 'post_tag', 'category' ),
    84             'public'      => true,
    85             'show_ui'     => true,
    86             'has_archive' => true,
    87             'rewrite'     => false,
    88             'menu_icon'   => 'dashicons-admin-plugins',
    89         ) );
    90 
    91         register_post_status( 'pending', array(
    92             'label' => _x( 'Pending', 'plugin status', 'wporg-plugins' ),
    93             'public' => false,
    94             'show_in_admin_status_list' => true,
    95             'label_count' => _n_noop( 'Pending <span class="count">(%s)</span>', 'Pending <span class="count">(%s)</span>', 'wporg-plugins' ),
    96         ) );
    97         register_post_status( 'disabled', array(
    98             'label' => _x( 'Disabled', 'plugin status', 'wporg-plugins' ),
    99             'public' => false,
    100             'show_in_admin_status_list' => true,
    101             'label_count' => _n_noop( 'Disabled <span class="count">(%s)</span>', 'Disabled <span class="count">(%s)</span>', 'wporg-plugins' ),
    102         ) );
    103         register_post_status( 'closed', array(
    104             'label' => _x( 'Closed', 'plugin status', 'wporg-plugins' ),
    105             'public' => false,
    106             'show_in_admin_status_list' => true,
    107             'label_count' => _n_noop( 'Closed <span class="count">(%s)</span>', 'Closed <span class="count">(%s)</span>', 'wporg-plugins' ),
    108         ) );
    109    
    110         // Add the browse/* views
    111         add_rewrite_tag( '%browse%', '(featured|popular|beta|new|favorites)' );
    112         add_permastruct( 'browse', 'browse/%browse%' );
    113 
    114         add_rewrite_endpoint( 'installation', EP_PERMALINK );
    115         add_rewrite_endpoint( 'faq',          EP_PERMALINK );
    116         add_rewrite_endpoint( 'screenshots',  EP_PERMALINK );
    117         add_rewrite_endpoint( 'changelog',    EP_PERMALINK );
    118         add_rewrite_endpoint( 'stats',        EP_PERMALINK );
    119         add_rewrite_endpoint( 'developers',   EP_PERMALINK );
    120         add_rewrite_endpoint( 'other_notes',  EP_PERMALINK );
    121     }
    122 
    123     /**
    124      * Filter the permalink for the Packages to be /post_name/
    125      *
    126      * @param string $link The generated permalink
    127      * @param string $post The package object
    128      * @return string
    129      */
    130     function package_link( $link, $post ) {
    131         if ( 'plugin' != $post->post_type ) {
    132             return $link;
    133         }
    134    
    135         return trailingslashit( home_url( $post->post_name ) );
    136     }
    137 
    138     /**
    139      * Checks if ther current users is a super admin before allowing terms to be added.
    140      *
    141      * @param string           $term The term to add or update.
    142      * @return string|WP_Error The term to add or update or WP_Error on failure.
    143      */
    144     function pre_insert_term_prevent( $term ) {
    145         if ( ! is_super_admin() ) {
    146             $term = new WP_Error( 'not-allowed', __( 'You are not allowed to add terms.', 'wporg-plugins' ) );
    147         }
    148    
    149         return $term;
    150     }
    151 
    152     function use_plugins_in_query( $wp_query ) {
    153         if ( ! $wp_query->is_main_query() ) {
    154             return;
    155         }
    156 
    157         if ( empty( $wp_query->query_vars['pagename'] ) &&
    158             ( empty( $wp_query->query_vars['post_type'] ) || 'posts' == $wp_query->query_vars['post_type'] ) ) {
    159             $wp_query->query_vars['post_type'] = array( 'plugin' );
    160         }
    161 
    162         if ( empty( $wp_query->query ) ) {
    163             $wp_query->query_vars['browse'] = 'featured';
    164         }
    165 
    166         switch ( get_query_var( 'browse' ) ) {
    167             case 'beta':
    168                 $wp_query->query_vars['category_name'] = 'beta';
    169                 break;
    170    
    171             case 'featured':
    172                 $wp_query->query_vars['category_name'] = 'featured';
    173                 break;
    174    
    175             case 'favorites':
    176                 break;
    177    
    178             case 'popular':
    179                 break;
    180         }
    181 
    182         // Re-route the Endpoints to the `content_page` query var.
    183         if ( !empty( $wp_query->query['name'] ) ) {
    184             foreach ( array( 'installation', 'faq', 'screenshots', 'changelog', 'stats', 'developers', 'other_notes' ) as $plugin_field ) {
    185                 if ( isset( $wp_query->query[ $plugin_field ] ) ) {
    186                     $wp_query->query['content_page'] = $wp_query->query_vars['content_page'] = $plugin_field;
    187                     unset( $wp_query->query[ $plugin_field ], $wp_query->query_vars[ $plugin_field ] );
    188                 }
    189             }
    190         }
    191     }
    192 
    193     function filter_post_content_to_correct_page( $content ) {
    194         global $content_pages;
    195 
    196         $post = get_post();
    197         if ( 'plugin' != $post->post_type ) {
    198             return $content;
    199         }
    200 
    201         $page = get_query_var( 'content_page' );
    202         $content_pages = $this->split_post_content_into_pages( $content );
    203 
    204         if ( ! isset( $content_pages[ $page ] ) ) {
    205             $page = 'description';
    206         }
    207 
    208         return $content_pages[ $page ];
    209     }
    210 
    211     function split_post_content_into_pages( $content ) {
    212         $content_pages = array(
    213             'stats' => '[wporg-plugins-stats]',
    214             'developers' => '[wporg-plugins-developer]',
    215         );
    216         $_pages = preg_split( "#<!--section=(.+?)-->#", $content, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
    217         for ( $i = 0; $i < count( $_pages ); $i += 2 ) {
    218             // Don't overwrite existing tabs.
    219             if ( ! isset( $content_pages[ $_pages[ $i ] ] ) ) {
    220                 $content_pages[ $_pages[ $i ] ] = $_pages[ $i + 1 ];
    221             }
    222         }
    223 
    224         return $content_pages;
    225     }
    226 
    227 }
    228 new Plugin_Directory();
    229 
    230 // Various functions used by other processes, will make sense to move to specific classses.
    231 class Plugin_Directory_Tools {
    232     static function get_readme_data( $readme ) {
    233         // Uses https://github.com/rmccue/WordPress-Readme-Parser (with modifications)
    234         include_once __DIR__ . '/readme-parser/markdown.php';
    235         include_once __DIR__ . '/readme-parser/compat.php';
    236 
    237         $data = (object) _WordPress_org_Readme::parse_readme( $readme );
    238 
    239         unset( $data->sections['screenshots'] ); // Useless
    240 
    241         // sanitize contributors.
    242         foreach ( $data->contributors as $i => $name ) {
    243             if ( get_user_by( 'login', $name ) ) {
    244                 continue;
    245             } elseif ( false !== ( $user = get_user_by( 'slug', $name ) ) ) {
    246                 $data->contributors[] = $user->user_login;
    247                 unset( $data->contributors[ $i ] );
    248             } else {
    249                 unset( $data->contributors[ $i ] );
    250             }
    251         }
    252 
    253         return $data;
    254     }
    255 }
    256 
    257 // Various helpers to retrieve data not stored within WordPress
    258 class Plugin_Directory_Template_Helpers {
    259     static function get_active_installs_count( $plugin_slug ) {
    260         global $wpdb;
    261    
    262         $count = wp_cache_get( $plugin_slug, 'plugin_active_installs' );
    263         if ( false === $count ) {
    264             $count = (int) $wpdb->get_var( $wpdb->prepare(
    265                 "SELECT count FROM rev2_daily_stat_summary WHERE type = 'plugin' AND type_name = %s AND stat = 'active_installs' LIMIT 1",
    266                 $plugin_slug
    267             ) );
    268             wp_cache_add( $plugin_slug, $count, 'plugin_active_installs', 1200 );
    269         }
    270    
    271         if ( $count < 10 ) {
    272             return 0;
    273         }
    274    
    275         if ( $count >= 1000000 ) {
    276             return 1000000;
    277         }
    278    
    279         return strval( $count )[0] * pow( 10, floor( log10( $count ) ) );
    280     }
    281 
    282     static function get_total_downloads() {
    283         global $wpdb;
    284 
    285         $count = wp_cache_get( 'plugin_download_count', 'plugin_download_count' );
    286         if ( false === $count ) {
    287             $count = (int) $wpdb->get_var( "SELECT SUM(downloads) FROM `plugin_2_stats`" );
    288             wp_cache_add( 'plugin_download_count', $count, 'plugin_download_count', DAY_IN_SECONDS );
    289         }
    290 
    291         return $count;
    292     }
    293 
    294     static function get_plugin_sections() {
    295         $plugin_slug  = get_post()->post_name;
    296         $raw_sections = get_post_meta( get_the_ID(), 'sections', true );
    297         $raw_sections = array_unique( array_merge( $raw_sections, array( 'description', 'stats', 'support', 'reviews', 'developers' ) ) );
    298    
    299         $sections = array();
    300         foreach ( $raw_sections as $section_slug ) {
    301             $url = get_permalink();
    302             switch ( $section_slug ) {
    303                 case 'description':
    304                     $title = _x( 'Description', 'plugin tab title', 'wporg-plugins' );
    305                     break;
    306                 case 'installation':
    307                     $title = _x( 'Installation', 'plugin tab title', 'wporg-plugins' );
    308                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    309                     break;
    310                 case 'faq':
    311                     $title = _x( 'FAQ', 'plugin tab title', 'wporg-plugins' );
    312                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    313                     break;
    314                 case 'screenshots':
    315                     $title = _x( 'Screenshots', 'plugin tab title', 'wporg-plugins' );
    316                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    317                     break;
    318                 case 'changelog':
    319                     $title = _x( 'Changelog', 'plugin tab title', 'wporg-plugins' );
    320                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    321                     break;
    322                 case 'stats':
    323                     $title = _x( 'Stats', 'plugin tab title', 'wporg-plugins' );
    324                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    325                     break;
    326                 case 'support':
    327                     $title = _x( 'Support', 'plugin tab title', 'wporg-plugins' );
    328                     $url = 'https://wordpress.org/support/plugin/' . $plugin_slug;
    329                     break;
    330                 case 'reviews':
    331                     $title = _x( 'Reviews', 'plugin tab title', 'wporg-plugins' );
    332                     $url = 'https://wordpress.org/support/view/plugin-reviews/' . $plugin_slug;
    333                     break;
    334                 case 'developers':
    335                     $title = _x( 'Developers', 'plugin tab title', 'wporg-plugins' );
    336                     $url = trailingslashit( $url ) . '/' . $section_slug . '/';
    337                     break;
    338             }
    339             $sections[] = array(
    340                 'slug'  => $section_slug,
    341                 'url'   => $url,
    342                 'title' => $title,
    343             );
    344         }
    345         return $sections;
    346     }
    347 }
    348    
     20$wporg_plugin_directory = new WPorg_Plugin_Directory();
     21register_activation_hook( __FILE__, array( $wporg_plugin_directory, 'activate' ) );
     22register_deactivation_hook( __FILE__, array( $wporg_plugin_directory, 'deactivate' ) );
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/readme-parser/ReadmeParser.php

    r2499 r2501  
    11<?php
    22/**
    3  * Custom readme parser
     3 * Custom readme parser.
    44 *
    55 * Based on Automattic_Readme from http://code.google.com/p/wordpress-plugin-readme-parser/
     
    1010 * @todo Create validator for this based on http://code.google.com/p/wordpress-plugin-readme-parser/source/browse/trunk/validator.php
    1111 */
     12
     13/**
     14 * Class Baikonur_ReadmeParser
     15 */
    1216class Baikonur_ReadmeParser {
    13 
    14     public static function parse_readme($file) {
    15         $contents = file($file);
    16         return self::parse_readme_contents($contents);
    17     }
    18 
    19     public static function parse_readme_contents($contents) {
    20         if (is_string($contents)) {
    21             $contents = explode("\n", $contents);
     17    public static function parse_readme( $file ) {
     18        $contents = file( $file );
     19
     20        return self::parse_readme_contents( $contents );
     21    }
     22
     23    public static function parse_readme_contents( $contents ) {
     24        if ( is_string( $contents ) ) {
     25            $contents = explode( "\n", $contents );
    2226        }
    2327
    2428        $this_class = __CLASS__;
    25         if (function_exists('get_called_class')) {
     29        if ( function_exists( 'get_called_class' ) ) {
    2630            $this_class = get_called_class();
    2731        }
    2832
    29         $contents = array_map(array($this_class, 'strip_newlines'), $contents);
     33        $contents = array_map( array( $this_class, 'strip_newlines' ), $contents );
    3034
    3135        // Strip BOM
    32         if (strpos($contents[0], "\xEF\xBB\xBF") === 0) {
    33             $contents[0] = substr($contents[0], 3);
     36        if ( strpos( $contents[0], "\xEF\xBB\xBF" ) === 0 ) {
     37            $contents[0] = substr( $contents[0], 3 );
    3438        }
    3539
     
    3741
    3842        // Defaults
    39         $data->is_excerpt = false;
    40         $data->is_truncated = false;
    41         $data->tags = array();
    42         $data->requires = '';
    43         $data->tested = '';
    44         $data->contributors = array();
    45         $data->stable_tag = '';
    46         $data->version = '';
    47         $data->donate_link = '';
     43        $data->is_excerpt        = false;
     44        $data->is_truncated      = false;
     45        $data->tags              = array();
     46        $data->requires          = '';
     47        $data->tested            = '';
     48        $data->contributors      = array();
     49        $data->stable_tag        = '';
     50        $data->version           = '';
     51        $data->donate_link       = '';
    4852        $data->short_description = '';
    49         $data->sections = array();
    50         $data->changelog = array();
    51         $data->upgrade_notice = array();
    52         $data->screenshots = array();
     53        $data->sections          = array();
     54        $data->changelog         = array();
     55        $data->upgrade_notice    = array();
     56        $data->screenshots       = array();
    5357        $data->remaining_content = array();
    5458
    55         $line = call_user_func_array(array($this_class, 'get_first_nonwhitespace'), array(&$contents));
     59        $line       = call_user_func_array( array( $this_class, 'get_first_nonwhitespace' ), array( &$contents ) );
    5660        $data->name = $line;
    57         $data->name = trim($data->name, "#= ");
     61        $data->name = trim( $data->name, "#= " );
    5862
    5963        // Parse headers
    6064        $headers = array();
    6165
    62         $line = call_user_func_array(array($this_class, 'get_first_nonwhitespace'), array(&$contents));
     66        $line = call_user_func_array( array( $this_class, 'get_first_nonwhitespace' ), array( &$contents ) );
    6367        do {
    6468            $key = $value = null;
    65             if (strpos($line, ':') === false) {
     69            if ( strpos( $line, ':' ) === false ) {
    6670                break;
    6771            }
    68             $bits = explode(':', $line, 2);
    69             list($key, $value) = $bits;
    70             $key = strtolower(str_replace(array(' ', "\t"), '_', trim($key)));
    71             if ($key === 'tags' && isset($headers['tags'])) {
    72                 $headers[$key] .= ',' . trim($value);
    73             }
    74             else {
    75                 $headers[$key] = trim($value);
    76             }
    77         }
    78         while (($line = array_shift($contents)) !== null && ($line = trim($line)) && !empty($line));
    79         array_unshift($contents, $line);
    80 
    81         if (!empty($headers['tags'])) {
    82             $data->tags = explode(',', $headers['tags']);
    83             $data->tags = array_map('trim', $data->tags);
    84         }
    85         if (!empty($headers['requires'])) {
     72            $bits = explode( ':', $line, 2 );
     73            list( $key, $value ) = $bits;
     74            $key = strtolower( str_replace( array( ' ', "\t" ), '_', trim( $key ) ) );
     75            if ( $key === 'tags' && isset( $headers['tags'] ) ) {
     76                $headers[ $key ] .= ',' . trim( $value );
     77            } else {
     78                $headers[ $key ] = trim( $value );
     79            }
     80        } while ( ( $line = array_shift( $contents ) ) !== null && ( $line = trim( $line ) ) && ! empty( $line ) );
     81        array_unshift( $contents, $line );
     82
     83        if ( ! empty( $headers['tags'] ) ) {
     84            $data->tags = explode( ',', $headers['tags'] );
     85            $data->tags = array_map( 'trim', $data->tags );
     86        }
     87        if ( ! empty( $headers['requires'] ) ) {
    8688            $data->requires = $headers['requires'];
    8789        }
    88         if (!empty($headers['requires_at_least'])) {
     90        if ( ! empty( $headers['requires_at_least'] ) ) {
    8991            $data->requires = $headers['requires_at_least'];
    9092        }
    91         if (!empty($headers['tested'])) {
     93        if ( ! empty( $headers['tested'] ) ) {
    9294            $data->tested = $headers['tested'];
    9395        }
    94         if (!empty($headers['tested_up_to'])) {
     96        if ( ! empty( $headers['tested_up_to'] ) ) {
    9597            $data->tested = $headers['tested_up_to'];
    9698        }
    97         if (!empty($headers['contributors'])) {
    98             $data->contributors = explode(',', $headers['contributors']);
    99             $data->contributors = array_map('trim', $data->contributors);
    100         }
    101         if (!empty($headers['stable_tag'])) {
     99        if ( ! empty( $headers['contributors'] ) ) {
     100            $data->contributors = explode( ',', $headers['contributors'] );
     101            $data->contributors = array_map( 'trim', $data->contributors );
     102        }
     103        if ( ! empty( $headers['stable_tag'] ) ) {
    102104            $data->stable_tag = $headers['stable_tag'];
    103105        }
    104         if (!empty($headers['donate_link'])) {
     106        if ( ! empty( $headers['donate_link'] ) ) {
    105107            $data->donate_link = $headers['donate_link'];
    106108        }
    107         if (!empty($headers['version'])) {
     109        if ( ! empty( $headers['version'] ) ) {
    108110            $data->version = $headers['version'];
    109         }
    110         else {
     111        } else {
    111112            $data->version = $data->stable_tag;
    112113        }
    113114
    114115        // Parse the short description
    115         while (($line = array_shift($contents)) !== null) {
    116             $trimmed = trim($line);
    117             if (empty($trimmed)) {
     116        while ( ( $line = array_shift( $contents ) ) !== null ) {
     117            $trimmed = trim( $line );
     118            if ( empty( $trimmed ) ) {
    118119                $data->short_description .= "\n";
    119120                continue;
    120121            }
    121             if ($trimmed[0] === '=' && isset($trimmed[1]) && $trimmed[1] === '=') {
    122                 array_unshift($contents, $line);
     122            if ( $trimmed[0] === '=' && isset( $trimmed[1] ) && $trimmed[1] === '=' ) {
     123                array_unshift( $contents, $line );
    123124                break;
    124125            }
     
    126127            $data->short_description .= $line . "\n";
    127128        }
    128         $data->short_description = trim($data->short_description);
    129 
    130         $data->is_truncated = call_user_func_array(array($this_class, 'trim_short_desc'), array(&$data->short_description));
     129        $data->short_description = trim( $data->short_description );
     130
     131        $data->is_truncated = call_user_func_array( array(
     132            $this_class,
     133            'trim_short_desc'
     134        ), array( &$data->short_description ) );
    131135
    132136        // Parse the rest of the body
    133137        $current = '';
    134         $special = array('description', 'installation', 'faq', 'frequently_asked_questions', 'screenshots', 'changelog', 'upgrade_notice');
    135 
    136         while (($line = array_shift($contents)) !== null) {
    137             $trimmed = trim($line);
    138             if (empty($trimmed)) {
     138        $special = array(
     139            'description',
     140            'installation',
     141            'faq',
     142            'frequently_asked_questions',
     143            'screenshots',
     144            'changelog',
     145            'upgrade_notice'
     146        );
     147
     148        while ( ( $line = array_shift( $contents ) ) !== null ) {
     149            $trimmed = trim( $line );
     150            if ( empty( $trimmed ) ) {
    139151                $current .= "\n";
    140152                continue;
    141153            }
    142154
    143             if ($trimmed[0] === '=' && isset($trimmed[1]) && $trimmed[1] === '=') {
    144                 if (!empty($title)) {
    145                     $data->sections[$title] = trim($current);
    146                 }
    147 
    148                 $current = '';
    149                 $real_title = trim($line, "#= \t");
    150                 $title = strtolower(str_replace(' ', '_', $real_title));
    151                 if ($title === 'faq') {
     155            if ( $trimmed[0] === '=' && isset( $trimmed[1] ) && $trimmed[1] === '=' ) {
     156                if ( ! empty( $title ) ) {
     157                    $data->sections[ $title ] = trim( $current );
     158                }
     159
     160                $current    = '';
     161                $real_title = trim( $line, "#= \t" );
     162                $title      = strtolower( str_replace( ' ', '_', $real_title ) );
     163                if ( $title === 'faq' ) {
    152164                    $title = 'frequently_asked_questions';
    153                 }
    154                 elseif ($title === 'change_log') {
     165                } elseif ( $title === 'change_log' ) {
    155166                    $title = 'changelog';
    156167                }
    157                 if (!in_array($title, $special)) {
     168                if ( ! in_array( $title, $special ) ) {
    158169                    $current .= '<h3>' . $real_title . "</h3>";
    159170                }
     
    164175        }
    165176
    166         if (!empty($title)) {
    167             $data->sections[$title] = trim($current);
    168         }
    169         $title = null;
     177        if ( ! empty( $title ) ) {
     178            $data->sections[ $title ] = trim( $current );
     179        }
     180        $title   = null;
    170181        $current = null;
    171182
    172         if (empty($data->sections['description'])) {
    173             $data->sections['description'] = call_user_func(array($this_class, 'parse_markdown'), $data->short_description);
     183        if ( empty( $data->sections['description'] ) ) {
     184            $data->sections['description'] = call_user_func( array(
     185                $this_class,
     186                'parse_markdown'
     187            ), $data->short_description );
    174188        }
    175189
    176190        // Parse changelog
    177         if (!empty($data->sections['changelog'])) {
    178             $lines = explode("\n", $data->sections['changelog']);
    179             while (($line = array_shift($lines)) !== null) {
    180                 $trimmed = trim($line);
    181                 if (empty($trimmed)) {
     191        if ( ! empty( $data->sections['changelog'] ) ) {
     192            $lines = explode( "\n", $data->sections['changelog'] );
     193            while ( ( $line = array_shift( $lines ) ) !== null ) {
     194                $trimmed = trim( $line );
     195                if ( empty( $trimmed ) ) {
    182196                    continue;
    183197                }
    184198
    185                 if ($trimmed[0] === '=') {
    186                     if (!empty($current)) {
    187                         $data->changelog[$title] = trim($current);
     199                if ( $trimmed[0] === '=' ) {
     200                    if ( ! empty( $current ) ) {
     201                        $data->changelog[ $title ] = trim( $current );
    188202                    }
    189203
    190204                    $current = '';
    191                     $title = trim($line, "#= \t");
     205                    $title   = trim( $line, "#= \t" );
    192206                    continue;
    193207                }
     
    196210            }
    197211
    198             $data->changelog[$title] = trim($current);
    199         }
    200         $title = null;
     212            $data->changelog[ $title ] = trim( $current );
     213        }
     214        $title   = null;
    201215        $current = null;
    202216
    203         if (isset($data->sections['upgrade_notice'])) {
    204             $lines = explode("\n", $data->sections['upgrade_notice']);
    205             while (($line = array_shift($lines)) !== null) {
    206                 $trimmed = trim($line);
    207                 if (empty($trimmed)) {
     217        if ( isset( $data->sections['upgrade_notice'] ) ) {
     218            $lines = explode( "\n", $data->sections['upgrade_notice'] );
     219            while ( ( $line = array_shift( $lines ) ) !== null ) {
     220                $trimmed = trim( $line );
     221                if ( empty( $trimmed ) ) {
    208222                    continue;
    209223                }
    210224
    211                 if ($trimmed[0] === '=') {
    212                     if (!empty($current)) {
    213                         $data->upgrade_notice[$title] = trim($current);
     225                if ( $trimmed[0] === '=' ) {
     226                    if ( ! empty( $current ) ) {
     227                        $data->upgrade_notice[ $title ] = trim( $current );
    214228                    }
    215229
    216230                    $current = '';
    217                     $title = trim($line, "#= \t");
     231                    $title   = trim( $line, "#= \t" );
    218232                    continue;
    219233                }
     
    222236            }
    223237
    224             if (!empty($title) && !empty($current)) {
    225                 $data->upgrade_notice[$title] = trim($current);
    226             }
    227             unset($data->sections['upgrade_notice']);
     238            if ( ! empty( $title ) && ! empty( $current ) ) {
     239                $data->upgrade_notice[ $title ] = trim( $current );
     240            }
     241            unset( $data->sections['upgrade_notice'] );
    228242        }
    229243
    230244        // Markdownify!
    231 
    232         $data->sections = array_map(array($this_class, 'parse_markdown'), $data->sections);
    233         $data->changelog = array_map(array($this_class, 'parse_markdown'), $data->changelog);
    234         $data->upgrade_notice = array_map(array($this_class, 'parse_markdown'), $data->upgrade_notice);
    235 
    236         if (isset($data->sections['screenshots'])) {
    237             preg_match_all('#<li>(.*?)</li>#is', $data->sections['screenshots'], $screenshots, PREG_SET_ORDER);
    238             if ($screenshots) {
    239                 foreach ((array) $screenshots as $ss) {
    240                     $data->screenshots[] = trim($ss[1]);
    241                 }
    242             }
    243         }
    244 
    245         // Rearrange stuff
    246 
     245        $data->sections       = array_map( array( $this_class, 'parse_markdown' ), $data->sections );
     246        $data->changelog      = array_map( array( $this_class, 'parse_markdown' ), $data->changelog );
     247        $data->upgrade_notice = array_map( array( $this_class, 'parse_markdown' ), $data->upgrade_notice );
     248
     249        if ( isset( $data->sections['screenshots'] ) ) {
     250            preg_match_all( '#<li>(.*?)</li>#is', $data->sections['screenshots'], $screenshots, PREG_SET_ORDER );
     251            if ( $screenshots ) {
     252                foreach ( (array) $screenshots as $ss ) {
     253                    $data->screenshots[] = trim( $ss[1] );
     254                }
     255            }
     256        }
     257
     258        // Rearrange stuff.
    247259        $data->remaining_content = $data->sections;
    248         $data->sections = array();
    249 
    250         foreach ($special as $spec) {
    251             if (isset($data->remaining_content[$spec])) {
    252                 $data->sections[$spec] = $data->remaining_content[$spec];
    253                 unset($data->remaining_content[$spec]);
     260        $data->sections          = array();
     261
     262        foreach ( $special as $spec ) {
     263            if ( isset( $data->remaining_content[ $spec ] ) ) {
     264                $data->sections[ $spec ] = $data->remaining_content[ $spec ];
     265                unset( $data->remaining_content[ $spec ] );
    254266            }
    255267        }
     
    258270    }
    259271
    260     protected static function get_first_nonwhitespace(&$contents) {
    261         while (($line = array_shift($contents)) !== null) {
    262             $trimmed = trim($line);
    263             if (!empty($line)) {
     272    protected static function get_first_nonwhitespace( &$contents ) {
     273        while ( ( $line = array_shift( $contents ) ) !== null ) {
     274            $trimmed = trim( $line );
     275            if ( ! empty( $line ) ) {
    264276                break;
    265277            }
     
    269281    }
    270282
    271     protected static function strip_newlines($line) {
    272         return rtrim($line, "\r\n");
    273     }
    274 
    275     protected static function trim_short_desc(&$desc) {
    276         if (function_exists('mb_strlen') && function_exists('mb_substr')) {
    277             if (mb_strlen($desc) > 150) {
    278                 $desc = mb_substr($desc, 0, 150);
    279                 $desc = trim($desc);
     283    protected static function strip_newlines( $line ) {
     284        return rtrim( $line, "\r\n" );
     285    }
     286
     287    protected static function trim_short_desc( &$desc ) {
     288        if ( function_exists( 'mb_strlen' ) && function_exists( 'mb_substr' ) ) {
     289            if ( mb_strlen( $desc ) > 150 ) {
     290                $desc = mb_substr( $desc, 0, 150 );
     291                $desc = trim( $desc );
     292
    280293                return true;
    281294            }
    282         }
    283         else {
    284             if (strlen($desc) > 150) {
    285                 $desc = substr($desc, 0, 150);
    286                 $desc = trim($desc);
     295        } else {
     296            if ( strlen( $desc ) > 150 ) {
     297                $desc = substr( $desc, 0, 150 );
     298                $desc = trim( $desc );
     299
    287300                return true;
    288301            }
     
    292305    }
    293306
    294     protected static function parse_markdown($text) {
    295         $text = self::code_trick($text);
    296         $text = preg_replace('/^[\s]*=[\s]+(.+?)[\s]+=/m', "\n" . '<h4>$1</h4>' . "\n", $text);
    297         $text = Markdown(trim($text));
    298         return trim($text);
    299     }
    300 
    301     protected static function code_trick($text) {
     307    protected static function parse_markdown( $text ) {
     308        $text = self::code_trick( $text );
     309        $text = preg_replace( '/^[\s]*=[\s]+(.+?)[\s]+=/m', "\n" . '<h4>$1</h4>' . "\n", $text );
     310        $text = Markdown( trim( $text ) );
     311
     312        return trim( $text );
     313    }
     314
     315    protected static function code_trick( $text ) {
    302316        // If doing markdown, first take any user formatted code blocks and turn them into backticks so that
    303317        // markdown will preserve things like underscores in code blocks
    304         $text = preg_replace_callback("!(<pre><code>|<code>)(.*?)(</code></pre>|</code>)!s", array(__CLASS__, 'decodeit'), $text);
    305 
    306         $text = str_replace(array("\r\n", "\r"), "\n", $text);
     318        $text = preg_replace_callback( "!(<pre><code>|<code>)(.*?)(</code></pre>|</code>)!s", array( __CLASS__, 'decodeit' ), $text );
     319        $text = str_replace( array( "\r\n", "\r" ), "\n", $text );
     320
    307321        // Markdown can do inline code, we convert bbPress style block level code to Markdown style
    308         $text = preg_replace_callback("!(^|\n)([ \t]*?)`(.*?)`!s", array(__CLASS__, 'indent'), $text);
     322        $text = preg_replace_callback( "!(^|\n)([ \t]*?)`(.*?)`!s", array( __CLASS__, 'indent' ), $text );
     323
    309324        return $text;
    310325    }
    311326
    312     protected static function indent($matches) {
     327    protected static function indent( $matches ) {
    313328        $text = $matches[3];
    314         $text = preg_replace('|^|m', $matches[2] . '    ', $text);
     329        $text = preg_replace( '|^|m', $matches[2] . '    ', $text );
     330
    315331        return $matches[1] . $text;
    316332    }
    317333
    318     protected static function decodeit($matches) {
    319         $text = $matches[2];
    320         $trans_table = array_flip(get_html_translation_table(HTML_ENTITIES));
    321         $text = strtr($text, $trans_table);
    322         $text = str_replace('<br />', '', $text);
    323         $text = str_replace('&#38;', '&', $text);
    324         $text = str_replace('&#39;', "'", $text);
    325         if ( '<pre><code>' == $matches[1] )
     334    protected static function decodeit( $matches ) {
     335        $text        = $matches[2];
     336        $trans_table = array_flip( get_html_translation_table( HTML_ENTITIES ) );
     337        $text        = strtr( $text, $trans_table );
     338        $text        = str_replace( '<br />', '', $text );
     339        $text        = str_replace( '&#38;', '&', $text );
     340        $text        = str_replace( '&#39;', "'", $text );
     341
     342            if ( '<pre><code>' == $matches[1] ) {
    326343            $text = "\n$text\n";
     344        }
     345
    327346        return "`$text`";
    328347    }
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/readme-parser/compat.php

    r2499 r2501  
    11<?php
     2/**
     3 * WordPress.org Plugin Readme Parser.
     4 *
     5 * @package WPorg_Plugin_Directory
     6 */
    27
    3 if ( !defined('WORDPRESS_README_MARKDOWN') ) {
    4     define('WORDPRESS_README_MARKDOWN', dirname(__FILE__) . '/markdown.php');
     8if ( ! defined( 'WORDPRESS_README_MARKDOWN' ) ) {
     9    define( 'WORDPRESS_README_MARKDOWN', dirname( __FILE__ ) . '/markdown.php' );
    510}
    611
    7 require_once(dirname(__FILE__) . '/ReadmeParser.php');
     12require_once( dirname( __FILE__ ) . '/ReadmeParser.php' );
    813
    9 class _WordPress_org_Readme extends Baikonur_ReadmeParser {
    10     public static function parse_readme($file) {
    11         $contents = file($file);
    12         return self::parse_readme_contents($contents);
     14/**
     15 * Class WPorg_Readme
     16 */
     17class WPorg_Readme extends Baikonur_ReadmeParser {
     18
     19    /**
     20     * @access public
     21     *
     22     * @param string $file File name.
     23     * @return array
     24     */
     25    public static function parse_readme( $file ) {
     26        $contents = file( $file );
     27
     28        return self::parse_readme_contents( $contents );
    1329    }
    1430
    15     public static function parse_readme_contents($contents) {
    16         if (empty($contents)) {
     31    /**
     32     * @access public
     33     *
     34     * @param array $contents
     35     * @return array
     36     */
     37    public static function parse_readme_contents( $contents ) {
     38        if ( empty( $contents ) ) {
    1739            return array();
    1840        }
    1941
    20         $result = parent::parse_readme_contents($contents);
    21         foreach ($result->sections as &$section) {
    22             $section = self::filter_text($section);
    23         }
    24         if (!empty($result->upgrade_notice)) {
    25             foreach ($result->upgrade_notice as &$notice) {
    26                 $notice = self::sanitize_text($notice);
    27             }
    28         }
    29         if (!empty($result->screenshots)) {
    30             foreach ($result->screenshots as &$shot) {
    31                 $shot = self::filter_text($shot);
    32             }
     42        $result = parent::parse_readme_contents( $contents );
     43        $result->sections = array_map( array( 'WPorg_Readme', 'filter_text' ), $result->sections );
     44
     45        if ( ! empty( $result->upgrade_notice ) ) {
     46            $result->upgrade_notice = array_map( array( 'WPorg_Readme', 'sanitize_text' ), $result->upgrade_notice );
    3347        }
    3448
    35         if (!empty($result->remaining_content)) {
    36             $result->remaining_content = implode("\n", $result->remaining_content);
    37             $result->remaining_content = self::filter_text(str_replace("</h3>\n\n", "</h3>\n", $result->remaining_content));
     49        if ( ! empty( $result->screenshots ) ) {
     50            $result->screenshots = array_map( array( 'WPorg_Readme', 'filter_text' ), $result->screenshots );
    3851        }
    39         else {
     52
     53        if ( ! empty( $result->remaining_content ) ) {
     54            $result->remaining_content = implode( "\n", $result->remaining_content );
     55            $result->remaining_content = self::filter_text( str_replace( "</h3>\n\n", "</h3>\n", $result->remaining_content ) );
     56        } else {
    4057            $result->remaining_content = '';
    4158        }
    4259
    43         $result->name = self::sanitize_text($result->name);
     60        $result->name = self::sanitize_text( $result->name );
    4461        //$result->short_description = self::sanitize_text($result->short_description);
    45         $result->donate_link = esc_url($result->donate_link);
     62        $result->donate_link = esc_url( $result->donate_link );
    4663
    4764        $result->requires_at_least = $result->requires;
    48         $result->tested_up_to = $result->tested;
    49         unset($result->requires, $result->tested);
    50         $result = ((array) $result);
    51         return $result;
     65        $result->tested_up_to      = $result->tested;
     66
     67        unset( $result->requires, $result->tested );
     68
     69        return (array) $result;
    5270    }
    5371
    54     protected static function trim_short_desc(&$desc) {
    55         $desc = self::sanitize_text($desc);
    56         return parent::trim_short_desc($desc);
     72    /**
     73     * @access protected
     74     *
     75     * @param string $desc
     76     * @return string
     77     */
     78    protected static function trim_short_desc( &$desc ) {
     79        $desc = self::sanitize_text( $desc );
     80        parent::trim_short_desc( $desc );
     81
     82        return $desc;
    5783    }
    5884
     85    /**
     86     * @access protected
     87     *
     88     * @param string $text
     89     * @return string
     90     */
    5991    protected static function sanitize_text( $text ) { // not fancy
    60         $text = strip_tags($text);
    61         $text = esc_html($text);
    62         $text = trim($text);
     92        $text = strip_tags( $text );
     93        $text = esc_html( $text );
     94        $text = trim( $text );
     95
    6396        return $text;
    6497    }
    6598
     99    /**
     100     * @access protected
     101     *
     102     * @param string $text
     103     * @return string
     104     */
    66105    protected static function filter_text( $text ) {
    67         $text = trim($text);
     106        $text = trim( $text );
    68107        //$text = self::code_trick($text); // A better parser than Markdown's for: backticks -> CODE
    69108
    70109        $allowed = array(
    71             'a' => array(
    72                 'href' => array(),
     110            'a'          => array(
     111                'href'  => array(),
    73112                'title' => array(),
    74                 'rel' => array()),
    75             'blockquote' => array('cite' => array()),
    76             'br' => array(),
    77             'p' => array(),
    78             'code' => array(),
    79             'pre' => array(),
    80             'em' => array(),
    81             'strong' => array(),
    82             'ul' => array(),
    83             'ol' => array(),
    84             'li' => array(),
    85             'h3' => array(),
    86             'h4' => array()
     113                'rel'   => array()
     114            ),
     115            'blockquote' => array( 'cite' => array() ),
     116            'br'         => array(),
     117            'p'          => array(),
     118            'code'       => array(),
     119            'pre'        => array(),
     120            'em'         => array(),
     121            'strong'     => array(),
     122            'ul'         => array(),
     123            'ol'         => array(),
     124            'li'         => array(),
     125            'h3'         => array(),
     126            'h4'         => array(),
    87127        );
    88128
    89         $text = balanceTags($text);
     129        $text = balanceTags( $text );
    90130
    91131        $text = wp_kses( $text, $allowed );
    92         $text = trim($text);
     132        $text = trim( $text );
     133
    93134        return $text;
    94135    }
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/readme-parser/markdown.php

    r2499 r2501  
    44#
    55# PHP Markdown & Extra
    6 # Copyright (c) 2004-2009 Michel Fortin 
     6# Copyright (c) 2004-2009 Michel Fortin
    77# <http://michelf.com/projects/php-markdown/>
    88#
    99# Original Markdown
    10 # Copyright (c) 2004-2006 John Gruber 
     10# Copyright (c) 2004-2006 John Gruber
    1111# <http://daringfireball.net/projects/markdown/>
    1212#
    1313
    14 
    15 define( 'MARKDOWN_VERSION',  "1.0.1n" ); # Sat 10 Oct 2009
    16 define( 'MARKDOWNEXTRA_VERSION',  "1.2.4" ); # Sat 10 Oct 2009
    17 
     14define( 'MARKDOWN_VERSION', "1.0.1n" ); # Sat 10 Oct 2009
     15define( 'MARKDOWNEXTRA_VERSION', "1.2.4" ); # Sat 10 Oct 2009
    1816
    1917#
     
    2220
    2321# Change to ">" for HTML output
    24 @define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX',  " />");
     22@define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX', " />" );
    2523
    2624# Define the width of a tab for code blocks.
    27 @define( 'MARKDOWN_TAB_WIDTH',     4 );
     25@define( 'MARKDOWN_TAB_WIDTH', 4 );
    2826
    2927# Optional title attribute for footnote links and backlinks.
    30 @define( 'MARKDOWN_FN_LINK_TITLE',         "" );
    31 @define( 'MARKDOWN_FN_BACKLINK_TITLE',     "" );
     28@define( 'MARKDOWN_FN_LINK_TITLE', "" );
     29@define( 'MARKDOWN_FN_BACKLINK_TITLE', "" );
    3230
    3331# Optional class attribute for footnote links and backlinks.
    34 @define( 'MARKDOWN_FN_LINK_CLASS',         "" );
    35 @define( 'MARKDOWN_FN_BACKLINK_CLASS',     "" );
    36 
     32@define( 'MARKDOWN_FN_LINK_CLASS', "" );
     33@define( 'MARKDOWN_FN_BACKLINK_CLASS', "" );
    3734
    3835#
     
    4138
    4239# Change to false to remove Markdown from posts and/or comments.
    43 @define( 'MARKDOWN_WP_POSTS',      true );
    44 @define( 'MARKDOWN_WP_COMMENTS',   true );
    45 
    46 
     40@define( 'MARKDOWN_WP_POSTS', true );
     41@define( 'MARKDOWN_WP_COMMENTS', true );
    4742
    4843### Standard Function Interface ###
    4944
    50 @define( 'MARKDOWN_PARSER_CLASS',  'MarkdownExtra_Parser' );
    51 
    52 function Markdown($text) {
     45@define( 'MARKDOWN_PARSER_CLASS', 'MarkdownExtra_Parser' );
     46
     47function Markdown( $text ) {
    5348#
    5449# Initialize the parser and return the result of its transform method.
     
    5651    # Setup static parser variable.
    5752    static $parser;
    58     if (!isset($parser)) {
     53    if ( ! isset( $parser ) ) {
    5954        $parser_class = MARKDOWN_PARSER_CLASS;
    60         $parser = new $parser_class;
     55        $parser       = new $parser_class;
    6156    }
    6257
    6358    # Transform text using parser.
    64     return $parser->transform($text);
     59    return $parser->transform( $text );
    6560}
    66 
    6761
    6862### WordPress Plugin Interface ###
     
    7771*/
    7872
    79 if (isset($wp_version)) {
     73if ( isset( $wp_version ) ) {
    8074    # More details about how it works here:
    8175    # <http://michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/>
    82    
     76
    8377    # Post content and excerpts
    8478    # - Remove WordPress paragraph generator.
    8579    # - Run Markdown on excerpt, then remove all tags.
    8680    # - Add paragraph tag around the excerpt, but remove it for the excerpt rss.
    87     if (MARKDOWN_WP_POSTS) {
    88         remove_filter('the_content',     'wpautop');
    89         remove_filter('the_content_rss', 'wpautop');
    90         remove_filter('the_excerpt',     'wpautop');
    91         add_filter('the_content',     'mdwp_MarkdownPost', 6);
    92         add_filter('the_content_rss', 'mdwp_MarkdownPost', 6);
    93         add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6);
    94         add_filter('get_the_excerpt', 'trim', 7);
    95         add_filter('the_excerpt',     'mdwp_add_p');
    96         add_filter('the_excerpt_rss', 'mdwp_strip_p');
    97        
    98         remove_filter('content_save_pre',  'balanceTags', 50);
    99         remove_filter('excerpt_save_pre',  'balanceTags', 50);
    100         add_filter('the_content',     'balanceTags', 50);
    101         add_filter('get_the_excerpt', 'balanceTags', 9);
    102     }
    103    
     81    if ( MARKDOWN_WP_POSTS ) {
     82        remove_filter( 'the_content', 'wpautop' );
     83        remove_filter( 'the_content_rss', 'wpautop' );
     84        remove_filter( 'the_excerpt', 'wpautop' );
     85        add_filter( 'the_content', 'mdwp_MarkdownPost', 6 );
     86        add_filter( 'the_content_rss', 'mdwp_MarkdownPost', 6 );
     87        add_filter( 'get_the_excerpt', 'mdwp_MarkdownPost', 6 );
     88        add_filter( 'get_the_excerpt', 'trim', 7 );
     89        add_filter( 'the_excerpt', 'mdwp_add_p' );
     90        add_filter( 'the_excerpt_rss', 'mdwp_strip_p' );
     91
     92        remove_filter( 'content_save_pre', 'balanceTags', 50 );
     93        remove_filter( 'excerpt_save_pre', 'balanceTags', 50 );
     94        add_filter( 'the_content', 'balanceTags', 50 );
     95        add_filter( 'get_the_excerpt', 'balanceTags', 9 );
     96    }
     97
    10498    # Add a footnote id prefix to posts when inside a loop.
    105     function mdwp_MarkdownPost($text) {
     99    function mdwp_MarkdownPost( $text ) {
    106100        static $parser;
    107         if (!$parser) {
     101        if ( ! $parser ) {
    108102            $parser_class = MARKDOWN_PARSER_CLASS;
    109             $parser = new $parser_class;
    110         }
    111         if (is_single() || is_page() || is_feed()) {
     103            $parser       = new $parser_class;
     104        }
     105        if ( is_single() || is_page() || is_feed() ) {
    112106            $parser->fn_id_prefix = "";
    113107        } else {
    114108            $parser->fn_id_prefix = get_the_ID() . ".";
    115109        }
    116         return $parser->transform($text);
    117     }
    118    
     110
     111        return $parser->transform( $text );
     112    }
     113
    119114    # Comments
    120115    # - Remove WordPress paragraph generator.
     
    122117    # - Scramble important tags before passing them to the kses filter.
    123118    # - Run Markdown on excerpt then remove paragraph tags.
    124     if (MARKDOWN_WP_COMMENTS) {
    125         remove_filter('comment_text', 'wpautop', 30);
    126         remove_filter('comment_text', 'make_clickable');
    127         add_filter('pre_comment_content', 'Markdown', 6);
    128         add_filter('pre_comment_content', 'mdwp_hide_tags', 8);
    129         add_filter('pre_comment_content', 'mdwp_show_tags', 12);
    130         add_filter('get_comment_text',    'Markdown', 6);
    131         add_filter('get_comment_excerpt', 'Markdown', 6);
    132         add_filter('get_comment_excerpt', 'mdwp_strip_p', 7);
    133    
     119    if ( MARKDOWN_WP_COMMENTS ) {
     120        remove_filter( 'comment_text', 'wpautop', 30 );
     121        remove_filter( 'comment_text', 'make_clickable' );
     122        add_filter( 'pre_comment_content', 'Markdown', 6 );
     123        add_filter( 'pre_comment_content', 'mdwp_hide_tags', 8 );
     124        add_filter( 'pre_comment_content', 'mdwp_show_tags', 12 );
     125        add_filter( 'get_comment_text', 'Markdown', 6 );
     126        add_filter( 'get_comment_excerpt', 'Markdown', 6 );
     127        add_filter( 'get_comment_excerpt', 'mdwp_strip_p', 7 );
     128
    134129        global $mdwp_hidden_tags, $mdwp_placeholders;
    135         $mdwp_hidden_tags = explode(' ',
    136             '<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>');
    137         $mdwp_placeholders = explode(' ', str_rot13(
    138             'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR '.
    139             'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli'));
    140     }
    141    
    142     function mdwp_add_p($text) {
    143         if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) {
    144             $text = '<p>'.$text.'</p>';
    145             $text = preg_replace('{\n{2,}}', "</p>\n\n<p>", $text);
    146         }
     130        $mdwp_hidden_tags  = explode( ' ',
     131            '<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>' );
     132        $mdwp_placeholders = explode( ' ', str_rot13(
     133            'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR ' .
     134            'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli' ) );
     135    }
     136
     137    function mdwp_add_p( $text ) {
     138        if ( ! preg_match( '{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text ) ) {
     139            $text = '<p>' . $text . '</p>';
     140            $text = preg_replace( '{\n{2,}}', "</p>\n\n<p>", $text );
     141        }
     142
    147143        return $text;
    148144    }
    149    
    150     function mdwp_strip_p($t) { return preg_replace('{</?p>}i', '', $t); }
    151 
    152     function mdwp_hide_tags($text) {
     145
     146    function mdwp_strip_p( $t ) {
     147        return preg_replace( '{</?p>}i', '', $t );
     148    }
     149
     150    function mdwp_hide_tags( $text ) {
    153151        global $mdwp_hidden_tags, $mdwp_placeholders;
    154         return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text);
    155     }
    156     function mdwp_show_tags($text) {
     152
     153        return str_replace( $mdwp_hidden_tags, $mdwp_placeholders, $text );
     154    }
     155
     156    function mdwp_show_tags( $text ) {
    157157        global $mdwp_hidden_tags, $mdwp_placeholders;
    158         return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text);
     158
     159        return str_replace( $mdwp_placeholders, $mdwp_hidden_tags, $text );
    159160    }
    160161}
    161 
    162162
    163163### bBlog Plugin Info ###
     
    165165function identify_modifier_markdown() {
    166166    return array(
    167         'name' => 'markdown',
    168         'type' => 'modifier',
    169         'nicename' => 'PHP Markdown Extra',
     167        'name'        => 'markdown',
     168        'type'        => 'modifier',
     169        'nicename'    => 'PHP Markdown Extra',
    170170        'description' => 'A text-to-HTML conversion tool for web writers',
    171         'authors' => 'Michel Fortin and John Gruber',
    172         'licence' => 'GPL',
    173         'version' => MARKDOWNEXTRA_VERSION,
    174         '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://michelf.com/projects/php-markdown/">More...</a>',
    175         );
     171        'authors'     => 'Michel Fortin and John Gruber',
     172        'licence'     => 'GPL',
     173        'version'     => MARKDOWNEXTRA_VERSION,
     174        '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://michelf.com/projects/php-markdown/">More...</a>',
     175    );
    176176}
    177177
    178 
    179178### Smarty Modifier Interface ###
    180179
    181 function smarty_modifier_markdown($text) {
    182     return Markdown($text);
     180function smarty_modifier_markdown( $text ) {
     181    return Markdown( $text );
    183182}
    184183
    185 
    186184### Textile Compatibility Mode ###
    187185
    188186# Rename this file to "classTextile.php" and it can replace Textile everywhere.
    189187
    190 if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) {
     188if ( strcasecmp( substr( __FILE__, - 16 ), "classTextile.php" ) == 0 ) {
    191189    # Try to include PHP SmartyPants. Should be in the same directory.
    192190    @include_once 'smartypants.php';
     191
    193192    # Fake Textile class. It calls Markdown instead.
    194193    class Textile {
    195         function TextileThis($text, $lite='', $encode='') {
    196             if ($lite == '' && $encode == '')    $text = Markdown($text);
    197             if (function_exists('SmartyPants'))  $text = SmartyPants($text);
     194        function TextileThis( $text, $lite = '', $encode = '' ) {
     195            if ( $lite == '' && $encode == '' ) {
     196                $text = Markdown( $text );
     197            }
     198            if ( function_exists( 'SmartyPants' ) ) {
     199                $text = SmartyPants( $text );
     200            }
     201
    198202            return $text;
    199203        }
     204
    200205        # Fake restricted version: restrictions are not supported for now.
    201         function TextileRestricted($text, $lite='', $noimage='') {
    202             return $this->TextileThis($text, $lite);
    203         }
     206        function TextileRestricted( $text, $lite = '', $noimage = '' ) {
     207            return $this->TextileThis( $text, $lite );
     208        }
     209
    204210        # Workaround to ensure compatibility with TextPattern 4.0.3.
    205         function blockLite($text) { return $text; }
     211        function blockLite( $text ) {
     212            return $text;
     213        }
    206214    }
    207215}
    208 
    209 
    210216
    211217#
     
    214220
    215221class Markdown_Parser {
    216 
    217222    # Regex to match balanced [brackets].
    218223    # Needed to insert a maximum bracked depth while converting to PHP.
    219224    var $nested_brackets_depth = 6;
    220225    var $nested_brackets_re;
    221    
    222226    var $nested_url_parenthesis_depth = 4;
    223227    var $nested_url_parenthesis_re;
    224 
    225228    # Table of hash values for escaped characters:
    226229    var $escape_chars = '\`*_{}[]()>#+-.!';
    227230    var $escape_chars_re;
    228 
    229231    # Change to ">" for HTML output.
    230232    var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
    231233    var $tab_width = MARKDOWN_TAB_WIDTH;
    232    
    233234    # Change to `true` to disallow markup or entities.
    234235    var $no_markup = false;
    235236    var $no_entities = false;
    236    
    237237    # Predefined urls and titles for reference links and images.
    238238    var $predef_urls = array();
    239239    var $predef_titles = array();
    240240
    241 
    242241    function Markdown_Parser() {
    243     #
    244     # Constructor function. Initialize appropriate member variables.
    245     #
     242        #
     243        # Constructor function. Initialize appropriate member variables.
     244        #
    246245        $this->_initDetab();
    247246        $this->prepareItalicsAndBold();
    248    
    249         $this->nested_brackets_re = 
    250             str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth).
    251             str_repeat('\])*', $this->nested_brackets_depth);
    252    
    253         $this->nested_url_parenthesis_re = 
    254             str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth).
    255             str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
    256        
    257         $this->escape_chars_re = '['.preg_quote($this->escape_chars).']';
    258        
     247
     248        $this->nested_brackets_re =
     249            str_repeat( '(?>[^\[\]]+|\[', $this->nested_brackets_depth ) .
     250            str_repeat( '\])*', $this->nested_brackets_depth );
     251
     252        $this->nested_url_parenthesis_re =
     253            str_repeat( '(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth ) .
     254            str_repeat( '(?>\)))*', $this->nested_url_parenthesis_depth );
     255
     256        $this->escape_chars_re = '[' . preg_quote( $this->escape_chars ) . ']';
     257
    259258        # Sort document, block, and span gamut in ascendent priority order.
    260         asort($this->document_gamut);
    261         asort($this->block_gamut);
    262         asort($this->span_gamut);
    263     }
    264 
     259        asort( $this->document_gamut );
     260        asort( $this->block_gamut );
     261        asort( $this->span_gamut );
     262    }
    265263
    266264    # Internal hashes used during transformation.
     
    268266    var $titles = array();
    269267    var $html_hashes = array();
    270    
    271268    # Status flag to avoid invalid nesting.
    272269    var $in_anchor = false;
    273    
    274    
     270
    275271    function setup() {
    276     #
    277     # Called before the transformation process starts to setup parser
    278     # states.
    279     #
     272        #
     273        # Called before the transformation process starts to setup parser
     274        # states.
     275        #
    280276        # Clear global hashes.
    281         $this->urls = $this->predef_urls;
    282         $this->titles = $this->predef_titles;
     277        $this->urls        = $this->predef_urls;
     278        $this->titles      = $this->predef_titles;
    283279        $this->html_hashes = array();
    284        
     280
    285281        $in_anchor = false;
    286282    }
    287    
     283
    288284    function teardown() {
    289     #
    290     # Called after the transformation process to clear any variable
    291     # which may be taking up memory unnecessarly.
    292     #
    293         $this->urls = array();
    294         $this->titles = array();
     285        #
     286        # Called after the transformation process to clear any variable
     287        # which may be taking up memory unnecessarly.
     288        #
     289        $this->urls        = array();
     290        $this->titles      = array();
    295291        $this->html_hashes = array();
    296292    }
    297293
    298 
    299     function transform($text) {
    300     #
    301     # Main function. Performs some preprocessing on the input text
    302     # and pass it through the document gamut.
    303     #
     294    function transform( $text ) {
     295        #
     296        # Main function. Performs some preprocessing on the input text
     297        # and pass it through the document gamut.
     298        #
    304299        $this->setup();
    305    
     300
    306301        # Remove UTF-8 BOM and marker character in input, if present.
    307         $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
     302        $text = preg_replace( '{^\xEF\xBB\xBF|\x1A}', '', $text );
    308303
    309304        # Standardize line endings:
    310305        #   DOS to Unix and Mac to Unix
    311         $text = preg_replace('{\r\n?}', "\n", $text);
     306        $text = preg_replace( '{\r\n?}', "\n", $text );
    312307
    313308        # Make sure $text ends with a couple of newlines:
     
    315310
    316311        # Convert all tabs to spaces.
    317         $text = $this->detab($text);
     312        $text = $this->detab( $text );
    318313
    319314        # Turn block-level HTML blocks into hash entries
    320         $text = $this->hashHTMLBlocks($text);
     315        $text = $this->hashHTMLBlocks( $text );
    321316
    322317        # Strip any lines consisting only of spaces and tabs.
     
    324319        # match consecutive blank lines with /\n+/ instead of something
    325320        # contorted like /[ ]*\n+/ .
    326         $text = preg_replace('/^[ ]+$/m', '', $text);
     321        $text = preg_replace( '/^[ ]+$/m', '', $text );
    327322
    328323        # Run document gamut methods.
    329         foreach ($this->document_gamut as $method => $priority) {
    330             $text = $this->$method($text);
    331         }
    332        
     324        foreach ( $this->document_gamut as $method => $priority ) {
     325            $text = $this->$method( $text );
     326        }
     327
    333328        $this->teardown();
    334329
    335330        return $text . "\n";
    336331    }
    337    
     332
    338333    var $document_gamut = array(
    339334        # Strip link definitions, store in hashes.
    340335        "stripLinkDefinitions" => 20,
    341        
    342336        "runBasicBlockGamut"   => 30,
    343         );
    344 
    345 
    346     function stripLinkDefinitions($text) {
    347     #
    348     # Strips link definitions from text, stores the URLs and titles in
    349     # hash references.
    350     #
     337    );
     338
     339    function stripLinkDefinitions( $text ) {
     340        #
     341        # Strips link definitions from text, stores the URLs and titles in
     342        # hash references.
     343        #
    351344        $less_than_tab = $this->tab_width - 1;
    352345
    353346        # Link defs are in the form: ^[id]: url "optional title"
    354         $text = preg_replace_callback('{
    355                             ^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1
     347        $text = preg_replace_callback( '{
     348                            ^[ ]{0,' . $less_than_tab . '}\[(.+)\][ ]?: # id = $1
    356349                              [ ]*
    357350                              \n?               # maybe *one* newline
     
    374367                            (?:\n+|\Z)
    375368            }xm',
    376             array(&$this, '_stripLinkDefinitions_callback'),
    377             $text);
     369            array( &$this, '_stripLinkDefinitions_callback' ),
     370            $text );
     371
    378372        return $text;
    379373    }
    380     function _stripLinkDefinitions_callback($matches) {
    381         $link_id = strtolower($matches[1]);
    382         $url = $matches[2] == '' ? $matches[3] : $matches[2];
    383         $this->urls[$link_id] = $url;
    384         $this->titles[$link_id] =& $matches[4];
     374
     375    function _stripLinkDefinitions_callback( $matches ) {
     376        $link_id                  = strtolower( $matches[1] );
     377        $url                      = $matches[2] == '' ? $matches[3] : $matches[2];
     378        $this->urls[ $link_id ]   = $url;
     379        $this->titles[ $link_id ] =& $matches[4];
     380
    385381        return ''; # String that will replace the block
    386382    }
    387383
    388 
    389     function hashHTMLBlocks($text) {
    390         if ($this->no_markup)  return $text;
     384    function hashHTMLBlocks( $text ) {
     385        if ( $this->no_markup ) {
     386            return $text;
     387        }
    391388
    392389        $less_than_tab = $this->tab_width - 1;
     
    400397        #
    401398        # *  List "a" is made of tags which can be both inline or block-level.
    402         #    These will be treated block-level when the start tag is alone on 
    403         #    its line, otherwise they're not matched here and will be taken as 
     399        #    These will be treated block-level when the start tag is alone on
     400        #    its line, otherwise they're not matched here and will be taken as
    404401        #    inline later.
    405402        # *  List "b" is made of tags which are always block-level;
    406403        #
    407404        $block_tags_a_re = 'ins|del';
    408         $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'.
    409                            'script|noscript|form|fieldset|iframe|math';
     405        $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|' .
     406                           'script|noscript|form|fieldset|iframe|math';
    410407
    411408        # Regular expression for the content of a block tag.
    412409        $nested_tags_level = 4;
    413         $attr = '
     410        $attr              = '
    414411            (?>             # optional tag attributes
    415412              \s            # starts with whitespace
     
    423420                \'[^\']*\'  # text inside single quotes (tolerate ">")
    424421              )*
    425             )? 
     422            )?
    426423            ';
    427         $content =
    428             str_repeat('
     424        $content           =
     425            str_repeat( '
    429426                (?>
    430427                  [^<]+         # content without tag
    431428                |
    432429                  <\2           # nested opening tag
    433                     '.$attr.'   # attributes
     430                    ' . $attr . '   # attributes
    434431                    (?>
    435432                      />
    436433                    |
    437                       >', $nested_tags_level).  # end of opening tag
    438                       '.*?'.                    # last level nested tag content
    439             str_repeat('
     434                      >', $nested_tags_level ) .    # end of opening tag
     435            '.*?' .                    # last level nested tag content
     436            str_repeat( '
    440437                      </\2\s*>  # closing nested tag
    441438                    )
    442                   |             
     439                  |
    443440                    <(?!/\2\s*> # other tags with a different name
    444441                  )
    445442                )*',
    446                 $nested_tags_level);
    447         $content2 = str_replace('\2', '\3', $content);
     443                $nested_tags_level );
     444        $content2          = str_replace( '\2', '\3', $content );
    448445
    449446        # First, look for nested blocks, e.g.:
     
    458455        # We need to do this before the next, more liberal match, because the next
    459456        # match will start at the first `<div>` and stop at the first `</div>`.
    460         $text = preg_replace_callback('{(?>
     457        $text = preg_replace_callback( '{(?>
    461458            (?>
    462459                (?<=\n\n)       # Starting after a blank line
     
    466463            (                       # save in $1
    467464
    468               # Match from `\n<tag>` to `</tag>\n`, handling nested tags 
     465              # Match from `\n<tag>` to `</tag>\n`, handling nested tags
    469466              # in between.
    470                    
    471                         [ ]{0,'.$less_than_tab.'}
    472                         <('.$block_tags_b_re.')# start tag = $2
    473                         '.$attr.'>          # attributes followed by > and \n
    474                         '.$content.'        # content, support nesting
     467
     468                        [ ]{0,' . $less_than_tab . '}
     469                        <(' . $block_tags_b_re . ')# start tag = $2
     470                        ' . $attr . '>          # attributes followed by > and \n
     471                        ' . $content . '        # content, support nesting
    475472                        </\2>               # the matching end tag
    476473                        [ ]*                # trailing spaces/tabs
     
    479476            | # Special version for tags of group a.
    480477
    481                         [ ]{0,'.$less_than_tab.'}
    482                         <('.$block_tags_a_re.')# start tag = $3
    483                         '.$attr.'>[ ]*\n    # attributes followed by >
    484                         '.$content2.'       # content, support nesting
     478                        [ ]{0,' . $less_than_tab . '}
     479                        <(' . $block_tags_a_re . ')# start tag = $3
     480                        ' . $attr . '>[ ]*\n    # attributes followed by >
     481                        ' . $content2 . '       # content, support nesting
    485482                        </\3>               # the matching end tag
    486483                        [ ]*                # trailing spaces/tabs
    487484                        (?=\n+|\Z)  # followed by a newline or end of document
    488                    
    489             | # Special case just for <hr />. It was easier to make a special 
     485
     486            | # Special case just for <hr />. It was easier to make a special
    490487              # case than to make the other regex more complicated.
    491            
    492                         [ ]{0,'.$less_than_tab.'}
     488
     489                        [ ]{0,' . $less_than_tab . '}
    493490                        <(hr)               # start tag = $2
    494                         '.$attr.'           # attributes
     491                        ' . $attr . '           # attributes
    495492                        /?>                 # the matching end tag
    496493                        [ ]*
    497494                        (?=\n{2,}|\Z)       # followed by a blank line or end of document
    498            
     495
    499496            | # Special case for standalone HTML comments:
    500            
    501                     [ ]{0,'.$less_than_tab.'}
     497
     498                    [ ]{0,' . $less_than_tab . '}
    502499                    (?s:
    503500                        <!-- .*? -->
     
    505502                    [ ]*
    506503                    (?=\n{2,}|\Z)       # followed by a blank line or end of document
    507            
     504
    508505            | # PHP and ASP-style processor instructions (<? and <%)
    509            
    510                     [ ]{0,'.$less_than_tab.'}
     506
     507                    [ ]{0,' . $less_than_tab . '}
    511508                    (?s:
    512509                        <([?%])         # $2
     
    516513                    [ ]*
    517514                    (?=\n{2,}|\Z)       # followed by a blank line or end of document
    518                    
     515
    519516            )
    520517            )}Sxmi',
    521             array(&$this, '_hashHTMLBlocks_callback'),
    522             $text);
     518            array( &$this, '_hashHTMLBlocks_callback' ),
     519            $text );
    523520
    524521        return $text;
    525522    }
    526     function _hashHTMLBlocks_callback($matches) {
     523
     524    function _hashHTMLBlocks_callback( $matches ) {
    527525        $text = $matches[1];
    528         $key  = $this->hashBlock($text);
     526        $key  = $this->hashBlock( $text );
     527
    529528        return "\n\n$key\n\n";
    530529    }
    531    
    532    
    533     function hashPart($text, $boundary = 'X') {
    534     #
    535     # Called whenever a tag must be hashed when a function insert an atomic
    536     # element in the text stream. Passing $text to through this function gives
    537     # a unique text-token which will be reverted back when calling unhash.
    538     #
    539     # The $boundary argument specify what character should be used to surround
    540     # the token. By convension, "B" is used for block elements that needs not
    541     # to be wrapped into paragraph tags at the end, ":" is used for elements
    542     # that are word separators and "X" is used in the general case.
    543     #
     530
     531    function hashPart( $text, $boundary = 'X' ) {
     532        #
     533        # Called whenever a tag must be hashed when a function insert an atomic
     534        # element in the text stream. Passing $text to through this function gives
     535        # a unique text-token which will be reverted back when calling unhash.
     536        #
     537        # The $boundary argument specify what character should be used to surround
     538        # the token. By convension, "B" is used for block elements that needs not
     539        # to be wrapped into paragraph tags at the end, ":" is used for elements
     540        # that are word separators and "X" is used in the general case.
     541        #
    544542        # Swap back any tag hash found in $text so we do not have to `unhash`
    545543        # multiple times at the end.
    546         $text = $this->unhash($text);
    547        
     544        $text = $this->unhash( $text );
     545
    548546        # Then hash the block.
    549547        static $i = 0;
    550         $key = "$boundary\x1A" . ++$i . $boundary;
    551         $this->html_hashes[$key] = $text;
     548        $key                       = "$boundary\x1A" . ++ $i . $boundary;
     549        $this->html_hashes[ $key ] = $text;
     550
    552551        return $key; # String that will replace the tag.
    553552    }
    554553
    555 
    556     function hashBlock($text) {
    557     #
    558     # Shortcut function for hashPart with block-level boundaries.
    559     #
    560         return $this->hashPart($text, 'B');
    561     }
    562 
     554    function hashBlock( $text ) {
     555        #
     556        # Shortcut function for hashPart with block-level boundaries.
     557        #
     558        return $this->hashPart( $text, 'B' );
     559    }
    563560
    564561    var $block_gamut = array(
    565     #
    566     # These are all the transformations that form block-level
    567     # tags like paragraphs, headers, and list items.
    568     #
     562        #
     563        # These are all the transformations that form block-level
     564        # tags like paragraphs, headers, and list items.
     565        #
    569566        "doHeaders"         => 10,
    570567        "doHorizontalRules" => 20,
    571        
    572568        "doLists"           => 40,
    573569        "doCodeBlocks"      => 50,
    574570        "doBlockQuotes"     => 60,
    575         );
    576 
    577     function runBlockGamut($text) {
    578     #
    579     # Run block gamut tranformations.
    580     #
    581         # We need to escape raw HTML in Markdown source before doing anything 
    582         # else. This need to be done for each block, and not only at the 
     571    );
     572
     573    function runBlockGamut( $text ) {
     574        #
     575        # Run block gamut tranformations.
     576        #
     577        # We need to escape raw HTML in Markdown source before doing anything
     578        # else. This need to be done for each block, and not only at the
    583579        # begining in the Markdown function since hashed blocks can be part of
    584         # list items and could have been indented. Indented blocks would have 
     580        # list items and could have been indented. Indented blocks would have
    585581        # been seen as a code block in a previous pass of hashHTMLBlocks.
    586         $text = $this->hashHTMLBlocks($text);
    587        
    588         return $this->runBasicBlockGamut($text);
    589     }
    590    
    591     function runBasicBlockGamut($text) {
    592     #
    593     # Run block gamut tranformations, without hashing HTML blocks. This is
    594     # useful when HTML blocks are known to be already hashed, like in the first
    595     # whole-document pass.
    596     #
    597         foreach ($this->block_gamut as $method => $priority) {
    598             $text = $this->$method($text);
    599         }
    600        
     582        $text = $this->hashHTMLBlocks( $text );
     583
     584        return $this->runBasicBlockGamut( $text );
     585    }
     586
     587    function runBasicBlockGamut( $text ) {
     588        #
     589        # Run block gamut tranformations, without hashing HTML blocks. This is
     590        # useful when HTML blocks are known to be already hashed, like in the first
     591        # whole-document pass.
     592        #
     593        foreach ( $this->block_gamut as $method => $priority ) {
     594            $text = $this->$method( $text );
     595        }
     596
    601597        # Finally form paragraph and restore hashed blocks.
    602         $text = $this->formParagraphs($text);
     598        $text = $this->formParagraphs( $text );
    603599
    604600        return $text;
    605601    }
    606    
    607    
    608     function doHorizontalRules($text) {
     602
     603    function doHorizontalRules( $text ) {
    609604        # Do Horizontal Rules:
    610605        return preg_replace(
     
    619614                $           # End of line.
    620615            }mx',
    621             "\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n",
    622             $text);
    623     }
    624 
     616            "\n" . $this->hashBlock( "<hr$this->empty_element_suffix" ) . "\n",
     617            $text );
     618    }
    625619
    626620    var $span_gamut = array(
    627     #
    628     # These are all the transformations that occur *within* block-level
    629     # tags like paragraphs, headers, and list items.
    630     #
     621        #
     622        # These are all the transformations that occur *within* block-level
     623        # tags like paragraphs, headers, and list items.
     624        #
    631625        # Process character escapes, code spans, and inline HTML
    632626        # in one shot.
    633         "parseSpan"           => -30,
    634 
     627        "parseSpan"           => - 30,
    635628        # Process anchor and image tags. Images must come first,
    636629        # because ![foo][f] looks like an anchor.
    637         "doImages"            =>  10,
    638         "doAnchors"           =>  20,
    639        
     630        "doImages"            => 10,
     631        "doAnchors"           => 20,
    640632        # Make links out of things like `<http://example.com/>`
    641633        # Must come after doAnchors, because you can use < and >
    642634        # delimiters in inline links like [this](<url>).
    643         "doAutoLinks"         =>  30,
    644         "encodeAmpsAndAngles" =>  40,
    645 
    646         "doItalicsAndBold"    =>  50,
    647         "doHardBreaks"        =>  60,
    648         );
    649 
    650     function runSpanGamut($text) {
    651     #
    652     # Run span gamut tranformations.
    653     #
    654         foreach ($this->span_gamut as $method => $priority) {
    655             $text = $this->$method($text);
     635        "doAutoLinks"         => 30,
     636        "encodeAmpsAndAngles" => 40,
     637        "doItalicsAndBold"    => 50,
     638        "doHardBreaks"        => 60,
     639    );
     640
     641    function runSpanGamut( $text ) {
     642        #
     643        # Run span gamut tranformations.
     644        #
     645        foreach ( $this->span_gamut as $method => $priority ) {
     646            $text = $this->$method( $text );
    656647        }
    657648
    658649        return $text;
    659650    }
    660    
    661    
    662     function doHardBreaks($text) {
     651
     652    function doHardBreaks( $text ) {
    663653        # Do hard breaks:
    664         return preg_replace_callback('/ {2,}\n/',
    665             array(&$this, '_doHardBreaks_callback'), $text);
    666     }
    667     function _doHardBreaks_callback($matches) {
    668         return $this->hashPart("<br$this->empty_element_suffix\n");
    669     }
    670 
    671 
    672     function doAnchors($text) {
    673     #
    674     # Turn Markdown link shortcuts into XHTML <a> tags.
    675     #
    676         if ($this->in_anchor) return $text;
     654        return preg_replace_callback( '/ {2,}\n/',
     655            array( &$this, '_doHardBreaks_callback' ), $text );
     656    }
     657
     658    function _doHardBreaks_callback( $matches ) {
     659        return $this->hashPart( "<br$this->empty_element_suffix\n" );
     660    }
     661
     662    function doAnchors( $text ) {
     663        #
     664        # Turn Markdown link shortcuts into XHTML <a> tags.
     665        #
     666        if ( $this->in_anchor ) {
     667            return $text;
     668        }
    677669        $this->in_anchor = true;
    678        
     670
    679671        #
    680672        # First, handle reference-style links: [link text] [id]
    681673        #
    682         $text = preg_replace_callback('{
     674        $text = preg_replace_callback( '{
    683675            (                   # wrap whole match in $1
    684676              \[
    685                 ('.$this->nested_brackets_re.') # link text = $2
     677                (' . $this->nested_brackets_re . ') # link text = $2
    686678              \]
    687679
     
    694686            )
    695687            }xs',
    696             array(&$this, '_doAnchors_reference_callback'), $text);
     688            array( &$this, '_doAnchors_reference_callback' ), $text );
    697689
    698690        #
    699691        # Next, inline-style links: [link text](url "optional title")
    700692        #
    701         $text = preg_replace_callback('{
     693        $text = preg_replace_callback( '{
    702694            (               # wrap whole match in $1
    703695              \[
    704                 ('.$this->nested_brackets_re.') # link text = $2
     696                (' . $this->nested_brackets_re . ') # link text = $2
    705697              \]
    706698              \(            # literal paren
     
    709701                    <(.+?)> # href = $3
    710702                |
    711                     ('.$this->nested_url_parenthesis_re.')  # href = $4
     703                    (' . $this->nested_url_parenthesis_re . ')  # href = $4
    712704                )
    713705                [ \n]*
     
    721713            )
    722714            }xs',
    723             array(&$this, '_doAnchors_inline_callback'), $text);
     715            array( &$this, '_doAnchors_inline_callback' ), $text );
    724716
    725717        #
     
    728720        # or [link text](/foo)
    729721        #
    730         $text = preg_replace_callback('{
     722        $text = preg_replace_callback( '{
    731723            (                   # wrap whole match in $1
    732724              \[
     
    735727            )
    736728            }xs',
    737             array(&$this, '_doAnchors_reference_callback'), $text);
     729            array( &$this, '_doAnchors_reference_callback' ), $text );
    738730
    739731        $this->in_anchor = false;
     732
    740733        return $text;
    741734    }
    742     function _doAnchors_reference_callback($matches) {
    743         $whole_match =  $matches[1];
    744         $link_text   =  $matches[2];
     735
     736    function _doAnchors_reference_callback( $matches ) {
     737        $whole_match = $matches[1];
     738        $link_text   = $matches[2];
    745739        $link_id     =& $matches[3];
    746740
    747         if ($link_id == "") {
     741        if ( $link_id == "" ) {
    748742            # for shortcut links like [this][] or [this].
    749743            $link_id = $link_text;
    750744        }
    751        
     745
    752746        # lower-case and turn embedded newlines into spaces
    753         $link_id = strtolower($link_id);
    754         $link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
    755 
    756         if (isset($this->urls[$link_id])) {
    757             $url = $this->urls[$link_id];
    758             $url = $this->encodeAttribute($url);
    759            
     747        $link_id = strtolower( $link_id );
     748        $link_id = preg_replace( '{[ ]?\n}', ' ', $link_id );
     749
     750        if ( isset( $this->urls[ $link_id ] ) ) {
     751            $url = $this->urls[ $link_id ];
     752            $url = $this->encodeAttribute( $url );
     753
    760754            $result = "<a href=\"$url\"";
    761             if ( isset( $this->titles[$link_id] ) ) {
    762                 $title = $this->titles[$link_id];
    763                 $title = $this->encodeAttribute($title);
    764                 $result .=  " title=\"$title\"";
    765             }
    766        
    767             $link_text = $this->runSpanGamut($link_text);
     755            if ( isset( $this->titles[ $link_id ] ) ) {
     756                $title = $this->titles[ $link_id ];
     757                $title = $this->encodeAttribute( $title );
     758                $result .= " title=\"$title\"";
     759            }
     760
     761            $link_text = $this->runSpanGamut( $link_text );
    768762            $result .= ">$link_text</a>";
    769             $result = $this->hashPart($result);
    770         }
    771         else {
     763            $result = $this->hashPart( $result );
     764        } else {
    772765            $result = $whole_match;
    773766        }
     767
    774768        return $result;
    775769    }
    776     function _doAnchors_inline_callback($matches) {
    777         $whole_match    =  $matches[1];
    778         $link_text      =  $this->runSpanGamut($matches[2]);
    779         $url            =  $matches[3] == '' ? $matches[4] : $matches[3];
    780         $title          =& $matches[7];
    781 
    782         $url = $this->encodeAttribute($url);
     770
     771    function _doAnchors_inline_callback( $matches ) {
     772        $whole_match = $matches[1];
     773        $link_text   = $this->runSpanGamut( $matches[2] );
     774        $url         = $matches[3] == '' ? $matches[4] : $matches[3];
     775        $title       =& $matches[7];
     776
     777        $url = $this->encodeAttribute( $url );
    783778
    784779        $result = "<a href=\"$url\"";
    785         if (isset($title)) {
    786             $title = $this->encodeAttribute($title);
    787             $result .=  " title=\"$title\"";
    788         }
    789        
    790         $link_text = $this->runSpanGamut($link_text);
     780        if ( isset( $title ) ) {
     781            $title = $this->encodeAttribute( $title );
     782            $result .= " title=\"$title\"";
     783        }
     784
     785        $link_text = $this->runSpanGamut( $link_text );
    791786        $result .= ">$link_text</a>";
    792787
    793         return $this->hashPart($result);
    794     }
    795 
    796 
    797     function doImages($text) {
    798     #
    799     # Turn Markdown image shortcuts into <img> tags.
    800     #
     788        return $this->hashPart( $result );
     789    }
     790
     791    function doImages( $text ) {
     792        #
     793        # Turn Markdown image shortcuts into <img> tags.
     794        #
    801795        #
    802796        # First, handle reference-style labeled images: ![alt text][id]
    803797        #
    804         $text = preg_replace_callback('{
     798        $text = preg_replace_callback( '{
    805799            (               # wrap whole match in $1
    806800              !\[
    807                 ('.$this->nested_brackets_re.')     # alt text = $2
     801                (' . $this->nested_brackets_re . ')     # alt text = $2
    808802              \]
    809803
     
    816810
    817811            )
    818             }xs', 
    819             array(&$this, '_doImages_reference_callback'), $text);
     812            }xs',
     813            array( &$this, '_doImages_reference_callback' ), $text );
    820814
    821815        #
     
    823817        # Don't forget: encode * and _
    824818        #
    825         $text = preg_replace_callback('{
     819        $text = preg_replace_callback( '{
    826820            (               # wrap whole match in $1
    827821              !\[
    828                 ('.$this->nested_brackets_re.')     # alt text = $2
     822                (' . $this->nested_brackets_re . ')     # alt text = $2
    829823              \]
    830824              \s?           # One optional whitespace character
     
    834828                    <(\S*)> # src url = $3
    835829                |
    836                     ('.$this->nested_url_parenthesis_re.')  # src url = $4
     830                    (' . $this->nested_url_parenthesis_re . ')  # src url = $4
    837831                )
    838832                [ \n]*
     
    846840            )
    847841            }xs',
    848             array(&$this, '_doImages_inline_callback'), $text);
     842            array( &$this, '_doImages_inline_callback' ), $text );
    849843
    850844        return $text;
    851845    }
    852     function _doImages_reference_callback($matches) {
     846
     847    function _doImages_reference_callback( $matches ) {
    853848        $whole_match = $matches[1];
    854849        $alt_text    = $matches[2];
    855         $link_id     = strtolower($matches[3]);
    856 
    857         if ($link_id == "") {
    858             $link_id = strtolower($alt_text); # for shortcut links like ![this][].
    859         }
    860 
    861         $alt_text = $this->encodeAttribute($alt_text);
    862         if (isset($this->urls[$link_id])) {
    863             $url = $this->encodeAttribute($this->urls[$link_id]);
     850        $link_id     = strtolower( $matches[3] );
     851
     852        if ( $link_id == "" ) {
     853            $link_id = strtolower( $alt_text ); # for shortcut links like ![this][].
     854        }
     855
     856        $alt_text = $this->encodeAttribute( $alt_text );
     857        if ( isset( $this->urls[ $link_id ] ) ) {
     858            $url    = $this->encodeAttribute( $this->urls[ $link_id ] );
    864859            $result = "<img src=\"$url\" alt=\"$alt_text\"";
    865             if (isset($this->titles[$link_id])) {
    866                 $title = $this->titles[$link_id];
    867                 $title = $this->encodeAttribute($title);
    868                 $result .=  " title=\"$title\"";
     860            if ( isset( $this->titles[ $link_id ] ) ) {
     861                $title = $this->titles[ $link_id ];
     862                $title = $this->encodeAttribute( $title );
     863                $result .= " title=\"$title\"";
    869864            }
    870865            $result .= $this->empty_element_suffix;
    871             $result = $this->hashPart($result);
    872         }
    873         else {
     866            $result = $this->hashPart( $result );
     867        } else {
    874868            # If there's no such link ID, leave intact:
    875869            $result = $whole_match;
     
    878872        return $result;
    879873    }
    880     function _doImages_inline_callback($matches) {
    881         $whole_match    = $matches[1];
    882         $alt_text       = $matches[2];
    883         $url            = $matches[3] == '' ? $matches[4] : $matches[3];
    884         $title          =& $matches[7];
    885 
    886         $alt_text = $this->encodeAttribute($alt_text);
    887         $url = $this->encodeAttribute($url);
    888         $result = "<img src=\"$url\" alt=\"$alt_text\"";
    889         if (isset($title)) {
    890             $title = $this->encodeAttribute($title);
    891             $result .=  " title=\"$title\""; # $title already quoted
     874
     875    function _doImages_inline_callback( $matches ) {
     876        $whole_match = $matches[1];
     877        $alt_text    = $matches[2];
     878        $url         = $matches[3] == '' ? $matches[4] : $matches[3];
     879        $title       =& $matches[7];
     880
     881        $alt_text = $this->encodeAttribute( $alt_text );
     882        $url      = $this->encodeAttribute( $url );
     883        $result   = "<img src=\"$url\" alt=\"$alt_text\"";
     884        if ( isset( $title ) ) {
     885            $title = $this->encodeAttribute( $title );
     886            $result .= " title=\"$title\""; # $title already quoted
    892887        }
    893888        $result .= $this->empty_element_suffix;
    894889
    895         return $this->hashPart($result);
    896     }
    897 
    898 
    899     function doHeaders($text) {
     890        return $this->hashPart( $result );
     891    }
     892
     893    function doHeaders( $text ) {
    900894        # Setext-style headers:
    901895        #     Header 1
    902896        #     ========
    903         # 
     897        #
    904898        #     Header 2
    905899        #     --------
    906900        #
    907         $text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
    908             array(&$this, '_doHeaders_callback_setext'), $text);
     901        $text = preg_replace_callback( '{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
     902            array( &$this, '_doHeaders_callback_setext' ), $text );
    909903
    910904        # atx-style headers:
     
    915909        #   ###### Header 6
    916910        #
    917         $text = preg_replace_callback('{
     911        $text = preg_replace_callback( '{
    918912                ^(\#{1,6})  # $1 = string of #\'s
    919913                [ ]*
     
    923917                \n+
    924918            }xm',
    925             array(&$this, '_doHeaders_callback_atx'), $text);
     919            array( &$this, '_doHeaders_callback_atx' ), $text );
    926920
    927921        return $text;
    928922    }
    929     function _doHeaders_callback_setext($matches) {
     923
     924    function _doHeaders_callback_setext( $matches ) {
    930925        # Terrible hack to check we haven't found an empty list item.
    931         if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1]))
     926        if ( $matches[2] == '-' && preg_match( '{^-(?: |$)}', $matches[1] ) ) {
    932927            return $matches[0];
    933        
     928        }
     929
    934930        $level = $matches[2]{0} == '=' ? 1 : 2;
    935         $block = "<h$level>".$this->runSpanGamut($matches[1])."</h$level>";
    936         return "\n" . $this->hashBlock($block) . "\n\n";
    937     }
    938     function _doHeaders_callback_atx($matches) {
    939         $level = strlen($matches[1]);
    940         $block = "<h$level>".$this->runSpanGamut($matches[2])."</h$level>";
    941         return "\n" . $this->hashBlock($block) . "\n\n";
    942     }
    943 
    944 
    945     function doLists($text) {
    946     #
    947     # Form HTML ordered (numbered) and unordered (bulleted) lists.
    948     #
     931        $block = "<h$level>" . $this->runSpanGamut( $matches[1] ) . "</h$level>";
     932
     933        return "\n" . $this->hashBlock( $block ) . "\n\n";
     934    }
     935
     936    function _doHeaders_callback_atx( $matches ) {
     937        $level = strlen( $matches[1] );
     938        $block = "<h$level>" . $this->runSpanGamut( $matches[2] ) . "</h$level>";
     939
     940        return "\n" . $this->hashBlock( $block ) . "\n\n";
     941    }
     942
     943    function doLists( $text ) {
     944        #
     945        # Form HTML ordered (numbered) and unordered (bulleted) lists.
     946        #
    949947        $less_than_tab = $this->tab_width - 1;
    950948
     
    957955            $marker_ul_re => $marker_ol_re,
    958956            $marker_ol_re => $marker_ul_re,
    959             );
    960 
    961         foreach ($markers_relist as $marker_re => $other_marker_re) {
     957        );
     958
     959        foreach ( $markers_relist as $marker_re => $other_marker_re ) {
    962960            # Re-usable pattern to match any entirel ul or ol list:
    963961            $whole_list_re = '
    964962                (                               # $1 = whole list
    965963                  (                             # $2
    966                     ([ ]{0,'.$less_than_tab.'}) # $3 = number of spaces
    967                     ('.$marker_re.')            # $4 = first list item marker
     964                    ([ ]{0,' . $less_than_tab . '}) # $3 = number of spaces
     965                    (' . $marker_re . ')            # $4 = first list item marker
    968966                    [ ]+
    969967                  )
     
    976974                      (?!                       # Negative lookahead for another list item marker
    977975                        [ ]*
    978                         '.$marker_re.'[ ]+
     976                        ' . $marker_re . '[ ]+
    979977                      )
    980978                    |
     
    982980                        \n
    983981                        \3                      # Must have the same indentation
    984                         '.$other_marker_re.'[ ]+
     982                        ' . $other_marker_re . '[ ]+
    985983                      )
    986984                  )
    987985                )
    988986            '; // mx
    989            
     987
    990988            # We use a different prefix before nested lists than top-level lists.
    991989            # See extended comment in _ProcessListItems().
    992        
    993             if ($this->list_level) {
    994                 $text = preg_replace_callback('{
     990
     991            if ( $this->list_level ) {
     992                $text = preg_replace_callback( '{
    995993                        ^
    996                         '.$whole_list_re.'
     994                        ' . $whole_list_re . '
    997995                    }mx',
    998                     array(&$this, '_doLists_callback'), $text);
    999             }
    1000             else {
    1001                 $text = preg_replace_callback('{
     996                    array( &$this, '_doLists_callback' ), $text );
     997            } else {
     998                $text = preg_replace_callback( '{
    1002999                        (?:(?<=\n)\n|\A\n?) # Must eat the newline
    1003                         '.$whole_list_re.'
     1000                        ' . $whole_list_re . '
    10041001                    }mx',
    1005                     array(&$this, '_doLists_callback'), $text);
     1002                    array( &$this, '_doLists_callback' ), $text );
    10061003            }
    10071004        }
     
    10091006        return $text;
    10101007    }
    1011     function _doLists_callback($matches) {
     1008
     1009    function _doLists_callback( $matches ) {
    10121010        # Re-usable patterns to match list item bullets and number markers:
    10131011        $marker_ul_re  = '[*+-]';
    10141012        $marker_ol_re  = '\d+[.]';
    10151013        $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
    1016        
    1017         $list = $matches[1];
    1018         $list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol";
    1019        
     1014
     1015        $list      = $matches[1];
     1016        $list_type = preg_match( "/$marker_ul_re/", $matches[4] ) ? "ul" : "ol";
     1017
    10201018        $marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re );
    1021        
     1019
    10221020        $list .= "\n";
    1023         $result = $this->processListItems($list, $marker_any_re);
    1024        
    1025         $result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>");
    1026         return "\n". $result ."\n\n";
     1021        $result = $this->processListItems( $list, $marker_any_re );
     1022
     1023        $result = $this->hashBlock( "<$list_type>\n" . $result . "</$list_type>" );
     1024
     1025        return "\n" . $result . "\n\n";
    10271026    }
    10281027
    10291028    var $list_level = 0;
    10301029
    1031     function processListItems($list_str, $marker_any_re) {
    1032     #
    1033     #   Process the contents of a single ordered or unordered list, splitting it
    1034     #   into individual list items.
    1035     #
     1030    function processListItems( $list_str, $marker_any_re ) {
     1031        #
     1032        #   Process the contents of a single ordered or unordered list, splitting it
     1033        #   into individual list items.
     1034        #
    10361035        # The $this->list_level global keeps track of when we're inside a list.
    10371036        # Each time we enter a list, we increment it; when we leave a list,
     
    10541053        # change the syntax rules such that sub-lists must start with a
    10551054        # starting cardinal number; e.g. "1." or "a.".
    1056        
    1057         $this->list_level++;
     1055
     1056        $this->list_level ++;
    10581057
    10591058        # trim trailing blank lines:
    1060         $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
    1061 
    1062         $list_str = preg_replace_callback('{
     1059        $list_str = preg_replace( "/\n{2,}\\z/", "\n", $list_str );
     1060
     1061        $list_str = preg_replace_callback( '{
    10631062            (\n)?                           # leading line = $1
    10641063            (^[ ]*)                         # leading whitespace = $2
    1065             ('.$marker_any_re.'             # list marker and space = $3
     1064            (' . $marker_any_re . '             # list marker and space = $3
    10661065                (?:[ ]+|(?=\n)) # space only required if item is not empty
    10671066            )
    10681067            ((?s:.*?))                      # list item text   = $4
    10691068            (?:(\n+(?=\n))|\n)              # tailing blank line = $5
    1070             (?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n))))
     1069            (?= \n* (\z | \2 (' . $marker_any_re . ') (?:[ ]+|(?=\n))))
    10711070            }xm',
    1072             array(&$this, '_processListItems_callback'), $list_str);
    1073 
    1074         $this->list_level--;
     1071            array( &$this, '_processListItems_callback' ), $list_str );
     1072
     1073        $this->list_level --;
     1074
    10751075        return $list_str;
    10761076    }
    1077     function _processListItems_callback($matches) {
    1078         $item = $matches[4];
    1079         $leading_line =& $matches[1];
    1080         $leading_space =& $matches[2];
    1081         $marker_space = $matches[3];
     1077
     1078    function _processListItems_callback( $matches ) {
     1079        $item               = $matches[4];
     1080        $leading_line       =& $matches[1];
     1081        $leading_space      =& $matches[2];
     1082        $marker_space       = $matches[3];
    10821083        $tailing_blank_line =& $matches[5];
    10831084
    1084         if ($leading_line || $tailing_blank_line ||
    1085             preg_match('/\n{2,}/', $item))
    1086         {
     1085        if ( $leading_line || $tailing_blank_line ||
     1086             preg_match( '/\n{2,}/', $item )
     1087        ) {
    10871088            # Replace marker with the appropriate whitespace indentation
    1088             $item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item;
    1089             $item = $this->runBlockGamut($this->outdent($item)."\n");
    1090         }
    1091         else {
     1089            $item = $leading_space . str_repeat( ' ', strlen( $marker_space ) ) . $item;
     1090            $item = $this->runBlockGamut( $this->outdent( $item ) . "\n" );
     1091        } else {
    10921092            # Recursion for sub-lists:
    1093             $item = $this->doLists($this->outdent($item));
    1094             $item = preg_replace('/\n+$/', '', $item);
    1095             $item = $this->runSpanGamut($item);
     1093            $item = $this->doLists( $this->outdent( $item ) );
     1094            $item = preg_replace( '/\n+$/', '', $item );
     1095            $item = $this->runSpanGamut( $item );
    10961096        }
    10971097
     
    10991099    }
    11001100
    1101 
    1102     function doCodeBlocks($text) {
    1103     #
    1104     #   Process Markdown `<pre><code>` blocks.
    1105     #
    1106         $text = preg_replace_callback('{
     1101    function doCodeBlocks( $text ) {
     1102        #
     1103        #   Process Markdown `<pre><code>` blocks.
     1104        #
     1105        $text = preg_replace_callback( '{
    11071106                (?:\n\n|\A\n?)
    11081107                (               # $1 = the code block -- one or more lines, starting with a space/tab
    11091108                  (?>
    1110                     [ ]{'.$this->tab_width.'}  # Lines must start with a tab or a tab-width of spaces
     1109                    [ ]{' . $this->tab_width . '}  # Lines must start with a tab or a tab-width of spaces
    11111110                    .*\n+
    11121111                  )+
    11131112                )
    1114                 ((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
     1113                ((?=^[ ]{0,' . $this->tab_width . '}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
    11151114            }xm',
    1116             array(&$this, '_doCodeBlocks_callback'), $text);
     1115            array( &$this, '_doCodeBlocks_callback' ), $text );
    11171116
    11181117        return $text;
    11191118    }
    1120     function _doCodeBlocks_callback($matches) {
     1119
     1120    function _doCodeBlocks_callback( $matches ) {
    11211121        $codeblock = $matches[1];
    11221122
    1123         $codeblock = $this->outdent($codeblock);
    1124         $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
     1123        $codeblock = $this->outdent( $codeblock );
     1124        $codeblock = htmlspecialchars( $codeblock, ENT_NOQUOTES );
    11251125
    11261126        # trim leading newlines and trailing newlines
    1127         $codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
     1127        $codeblock = preg_replace( '/\A\n+|\n+\z/', '', $codeblock );
    11281128
    11291129        $codeblock = "<pre><code>$codeblock\n</code></pre>";
    1130         return "\n\n".$this->hashBlock($codeblock)."\n\n";
    1131     }
    1132 
    1133 
    1134     function makeCodeSpan($code) {
    1135     #
    1136     # Create a code span markup for $code. Called from handleSpanToken.
    1137     #
    1138         $code = htmlspecialchars(trim($code), ENT_NOQUOTES);
    1139         return $this->hashPart("<code>$code</code>");
    1140     }
    1141 
     1130
     1131        return "\n\n" . $this->hashBlock( $codeblock ) . "\n\n";
     1132    }
     1133
     1134    function makeCodeSpan( $code ) {
     1135        #
     1136        # Create a code span markup for $code. Called from handleSpanToken.
     1137        #
     1138        $code = htmlspecialchars( trim( $code ), ENT_NOQUOTES );
     1139
     1140        return $this->hashPart( "<code>$code</code>" );
     1141    }
    11421142
    11431143    var $em_relist = array(
     
    11451145        '*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
    11461146        '_' => '(?<=\S|^)(?<!_)_(?!_)',
    1147         );
     1147    );
    11481148    var $strong_relist = array(
    11491149        ''   => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S|$)(?![.,:;]\s)',
    11501150        '**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
    11511151        '__' => '(?<=\S|^)(?<!_)__(?!_)',
    1152         );
     1152    );
    11531153    var $em_strong_relist = array(
    11541154        ''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S|$)(?![.,:;]\s)',
    11551155        '***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
    11561156        '___' => '(?<=\S|^)(?<!_)___(?!_)',
    1157         );
     1157    );
    11581158    var $em_strong_prepared_relist;
    1159    
     1159
    11601160    function prepareItalicsAndBold() {
    1161     #
    1162     # Prepare regular expressions for searching emphasis tokens in any
    1163     # context.
    1164     #
    1165         foreach ($this->em_relist as $em => $em_re) {
    1166             foreach ($this->strong_relist as $strong => $strong_re) {
     1161        #
     1162        # Prepare regular expressions for searching emphasis tokens in any
     1163        # context.
     1164        #
     1165        foreach ( $this->em_relist as $em => $em_re ) {
     1166            foreach ( $this->strong_relist as $strong => $strong_re ) {
    11671167                # Construct list of allowed token expressions.
    11681168                $token_relist = array();
    1169                 if (isset($this->em_strong_relist["$em$strong"])) {
     1169                if ( isset( $this->em_strong_relist["$em$strong"] ) ) {
    11701170                    $token_relist[] = $this->em_strong_relist["$em$strong"];
    11711171                }
    11721172                $token_relist[] = $em_re;
    11731173                $token_relist[] = $strong_re;
    1174                
     1174
    11751175                # Construct master expression from list.
    1176                 $token_re = '{('. implode('|', $token_relist) .')}';
     1176                $token_re                                      = '{(' . implode( '|', $token_relist ) . ')}';
    11771177                $this->em_strong_prepared_relist["$em$strong"] = $token_re;
    11781178            }
    11791179        }
    11801180    }
    1181    
    1182     function doItalicsAndBold($text) {
    1183         $token_stack = array('');
    1184         $text_stack = array('');
    1185         $em = '';
    1186         $strong = '';
     1181
     1182    function doItalicsAndBold( $text ) {
     1183        $token_stack  = array( '' );
     1184        $text_stack   = array( '' );
     1185        $em           = '';
     1186        $strong       = '';
    11871187        $tree_char_em = false;
    1188        
    1189         while (1) {
     1188
     1189        while ( 1 ) {
    11901190            #
    11911191            # Get prepared regular expression for seraching emphasis tokens
     
    11931193            #
    11941194            $token_re = $this->em_strong_prepared_relist["$em$strong"];
    1195            
     1195
    11961196            #
    1197             # Each loop iteration search for the next emphasis token. 
     1197            # Each loop iteration search for the next emphasis token.
    11981198            # Each token is then passed to handleSpanToken.
    11991199            #
    1200             $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
     1200            $parts = preg_split( $token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE );
    12011201            $text_stack[0] .= $parts[0];
    12021202            $token =& $parts[1];
    1203             $text =& $parts[2];
    1204            
    1205             if (empty($token)) {
     1203            $text  =& $parts[2];
     1204
     1205            if ( empty( $token ) ) {
    12061206                # Reached end of text span: empty stack without emitting.
    12071207                # any more emphasis.
    1208                 while ($token_stack[0]) {
    1209                     $text_stack[1] .= array_shift($token_stack);
    1210                     $text_stack[0] .= array_shift($text_stack);
     1208                while ( $token_stack[0] ) {
     1209                    $text_stack[1] .= array_shift( $token_stack );
     1210                    $text_stack[0] .= array_shift( $text_stack );
    12111211                }
    12121212                break;
    12131213            }
    1214            
    1215             $token_len = strlen($token);
    1216             if ($tree_char_em) {
     1214
     1215            $token_len = strlen( $token );
     1216            if ( $tree_char_em ) {
    12171217                # Reached closing marker while inside a three-char emphasis.
    1218                 if ($token_len == 3) {
     1218                if ( $token_len == 3 ) {
    12191219                    # Three-char closing marker, close em and strong.
    1220                     array_shift($token_stack);
    1221                     $span = array_shift($text_stack);
    1222                     $span = $this->runSpanGamut($span);
     1220                    array_shift( $token_stack );
     1221                    $span = array_shift( $text_stack );
     1222                    $span = $this->runSpanGamut( $span );
    12231223                    $span = "<strong><em>$span</em></strong>";
    1224                     $text_stack[0] .= $this->hashPart($span);
    1225                     $em = '';
     1224                    $text_stack[0] .= $this->hashPart( $span );
     1225                    $em     = '';
    12261226                    $strong = '';
    12271227                } else {
    12281228                    # Other closing marker: close one em or strong and
    12291229                    # change current token state to match the other
    1230                     $token_stack[0] = str_repeat($token{0}, 3-$token_len);
    1231                     $tag = $token_len == 2 ? "strong" : "em";
    1232                     $span = $text_stack[0];
    1233                     $span = $this->runSpanGamut($span);
    1234                     $span = "<$tag>$span</$tag>";
    1235                     $text_stack[0] = $this->hashPart($span);
    1236                     $$tag = ''; # $$tag stands for $em or $strong
     1230                    $token_stack[0] = str_repeat( $token{0}, 3 - $token_len );
     1231                    $tag            = $token_len == 2 ? "strong" : "em";
     1232                    $span           = $text_stack[0];
     1233                    $span           = $this->runSpanGamut( $span );
     1234                    $span           = "<$tag>$span</$tag>";
     1235                    $text_stack[0]  = $this->hashPart( $span );
     1236                    $$tag           = ''; # $$tag stands for $em or $strong
    12371237                }
    12381238                $tree_char_em = false;
    1239             } else if ($token_len == 3) {
    1240                 if ($em) {
     1239            } else if ( $token_len == 3 ) {
     1240                if ( $em ) {
    12411241                    # Reached closing marker for both em and strong.
    12421242                    # Closing strong marker:
    1243                     for ($i = 0; $i < 2; ++$i) {
    1244                         $shifted_token = array_shift($token_stack);
    1245                         $tag = strlen($shifted_token) == 2 ? "strong" : "em";
    1246                         $span = array_shift($text_stack);
    1247                         $span = $this->runSpanGamut($span);
    1248                         $span = "<$tag>$span</$tag>";
    1249                         $text_stack[0] .= $this->hashPart($span);
     1243                    for ( $i = 0; $i < 2; ++ $i ) {
     1244                        $shifted_token = array_shift( $token_stack );
     1245                        $tag           = strlen( $shifted_token ) == 2 ? "strong" : "em";
     1246                        $span          = array_shift( $text_stack );
     1247                        $span          = $this->runSpanGamut( $span );
     1248                        $span          = "<$tag>$span</$tag>";
     1249                        $text_stack[0] .= $this->hashPart( $span );
    12501250                        $$tag = ''; # $$tag stands for $em or $strong
    12511251                    }
    12521252                } else {
    1253                     # Reached opening three-char emphasis marker. Push on token 
     1253                    # Reached opening three-char emphasis marker. Push on token
    12541254                    # stack; will be handled by the special condition above.
    1255                     $em = $token{0};
     1255                    $em     = $token{0};
    12561256                    $strong = "$em$em";
    1257                     array_unshift($token_stack, $token);
    1258                     array_unshift($text_stack, '');
     1257                    array_unshift( $token_stack, $token );
     1258                    array_unshift( $text_stack, '' );
    12591259                    $tree_char_em = true;
    12601260                }
    1261             } else if ($token_len == 2) {
    1262                 if ($strong) {
     1261            } else if ( $token_len == 2 ) {
     1262                if ( $strong ) {
    12631263                    # Unwind any dangling emphasis marker:
    1264                     if (strlen($token_stack[0]) == 1) {
    1265                         $text_stack[1] .= array_shift($token_stack);
    1266                         $text_stack[0] .= array_shift($text_stack);
     1264                    if ( strlen( $token_stack[0] ) == 1 ) {
     1265                        $text_stack[1] .= array_shift( $token_stack );
     1266                        $text_stack[0] .= array_shift( $text_stack );
    12671267                    }
    12681268                    # Closing strong marker:
    1269                     array_shift($token_stack);
    1270                     $span = array_shift($text_stack);
    1271                     $span = $this->runSpanGamut($span);
     1269                    array_shift( $token_stack );
     1270                    $span = array_shift( $text_stack );
     1271                    $span = $this->runSpanGamut( $span );
    12721272                    $span = "<strong>$span</strong>";
    1273                     $text_stack[0] .= $this->hashPart($span);
     1273                    $text_stack[0] .= $this->hashPart( $span );
    12741274                    $strong = '';
    12751275                } else {
    1276                     array_unshift($token_stack, $token);
    1277                     array_unshift($text_stack, '');
     1276                    array_unshift( $token_stack, $token );
     1277                    array_unshift( $text_stack, '' );
    12781278                    $strong = $token;
    12791279                }
    12801280            } else {
    12811281                # Here $token_len == 1
    1282                 if ($em) {
    1283                     if (strlen($token_stack[0]) == 1) {
     1282                if ( $em ) {
     1283                    if ( strlen( $token_stack[0] ) == 1 ) {
    12841284                        # Closing emphasis marker:
    1285                         array_shift($token_stack);
    1286                         $span = array_shift($text_stack);
    1287                         $span = $this->runSpanGamut($span);
     1285                        array_shift( $token_stack );
     1286                        $span = array_shift( $text_stack );
     1287                        $span = $this->runSpanGamut( $span );
    12881288                        $span = "<em>$span</em>";
    1289                         $text_stack[0] .= $this->hashPart($span);
     1289                        $text_stack[0] .= $this->hashPart( $span );
    12901290                        $em = '';
    12911291                    } else {
     
    12931293                    }
    12941294                } else {
    1295                     array_unshift($token_stack, $token);
    1296                     array_unshift($text_stack, '');
     1295                    array_unshift( $token_stack, $token );
     1296                    array_unshift( $text_stack, '' );
    12971297                    $em = $token;
    12981298                }
    12991299            }
    13001300        }
     1301
    13011302        return $text_stack[0];
    13021303    }
    13031304
    1304 
    1305     function doBlockQuotes($text) {
    1306         $text = preg_replace_callback('/
     1305    function doBlockQuotes( $text ) {
     1306        $text = preg_replace_callback( '/
    13071307              (                             # Wrap whole match in $1
    13081308                (?>
     
    13141314              )
    13151315            /xm',
    1316             array(&$this, '_doBlockQuotes_callback'), $text);
     1316            array( &$this, '_doBlockQuotes_callback' ), $text );
    13171317
    13181318        return $text;
    13191319    }
    1320     function _doBlockQuotes_callback($matches) {
     1320
     1321    function _doBlockQuotes_callback( $matches ) {
    13211322        $bq = $matches[1];
    13221323        # trim one level of quoting - trim whitespace-only lines
    1323         $bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
    1324         $bq = $this->runBlockGamut($bq);        # recurse
    1325 
    1326         $bq = preg_replace('/^/m', "  ", $bq);
    1327         # These leading spaces cause problem with <pre> content, 
     1324        $bq = preg_replace( '/^[ ]*>[ ]?|^[ ]+$/m', '', $bq );
     1325        $bq = $this->runBlockGamut( $bq );        # recurse
     1326
     1327        $bq = preg_replace( '/^/m', "  ", $bq );
     1328        # These leading spaces cause problem with <pre> content,
    13281329        # so we need to fix that:
    1329         $bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx',
    1330             array(&$this, '_doBlockQuotes_callback2'), $bq);
    1331 
    1332         return "\n". $this->hashBlock("<blockquote>\n$bq\n</blockquote>")."\n\n";
    1333     }
    1334     function _doBlockQuotes_callback2($matches) {
     1330        $bq = preg_replace_callback( '{(\s*<pre>.+?</pre>)}sx',
     1331            array( &$this, '_doBlockQuotes_callback2' ), $bq );
     1332
     1333        return "\n" . $this->hashBlock( "<blockquote>\n$bq\n</blockquote>" ) . "\n\n";
     1334    }
     1335
     1336    function _doBlockQuotes_callback2( $matches ) {
    13351337        $pre = $matches[1];
    1336         $pre = preg_replace('/^  /m', '', $pre);
     1338        $pre = preg_replace( '/^  /m', '', $pre );
     1339
    13371340        return $pre;
    13381341    }
    13391342
    1340 
    1341     function formParagraphs($text) {
    1342     #
    1343     #   Params:
    1344     #       $text - string to process with html <p> tags
    1345     #
     1343    function formParagraphs( $text ) {
     1344        #
     1345        #   Params:
     1346        #       $text - string to process with html <p> tags
     1347        #
    13461348        # Strip leading and trailing lines:
    1347         $text = preg_replace('/\A\n+|\n+\z/', '', $text);
    1348 
    1349         $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
     1349        $text = preg_replace( '/\A\n+|\n+\z/', '', $text );
     1350
     1351        $grafs = preg_split( '/\n{2,}/', $text, - 1, PREG_SPLIT_NO_EMPTY );
    13501352
    13511353        #
    13521354        # Wrap <p> tags and unhashify HTML blocks
    13531355        #
    1354         foreach ($grafs as $key => $value) {
    1355             if (!preg_match('/^B\x1A[0-9]+B$/', $value)) {
     1356        foreach ( $grafs as $key => $value ) {
     1357            if ( ! preg_match( '/^B\x1A[0-9]+B$/', $value ) ) {
    13561358                # Is a paragraph.
    1357                 $value = $this->runSpanGamut($value);
    1358                 $value = preg_replace('/^([ ]*)/', "<p>", $value);
     1359                $value = $this->runSpanGamut( $value );
     1360                $value = preg_replace( '/^([ ]*)/', "<p>", $value );
    13591361                $value .= "</p>";
    1360                 $grafs[$key] = $this->unhash($value);
    1361             }
    1362             else {
     1362                $grafs[ $key ] = $this->unhash( $value );
     1363            } else {
    13631364                # Is a block.
    13641365                # Modify elements of @grafs in-place...
    1365                 $graf = $value;
    1366                 $block = $this->html_hashes[$graf];
    1367                 $graf = $block;
     1366                $graf  = $value;
     1367                $block = $this->html_hashes[ $graf ];
     1368                $graf  = $block;
    13681369//              if (preg_match('{
    13691370//                  \A
     
    13901391//                  # that initialization code should be pulled into its own sub, though.
    13911392//                  $div_content = $this->hashHTMLBlocks($div_content);
    1392 //                 
     1393//
    13931394//                  # Run document gamut methods on the content.
    13941395//                  foreach ($this->document_gamut as $method => $priority) {
     
    14011402//                  $graf = $div_open . "\n" . $div_content . "\n" . $div_close;
    14021403//              }
    1403                 $grafs[$key] = $graf;
    1404             }
    1405         }
    1406 
    1407         return implode("\n\n", $grafs);
    1408     }
    1409 
    1410 
    1411     function encodeAttribute($text) {
    1412     #
    1413     # Encode text for a double-quoted HTML attribute. This function
    1414     # is *not* suitable for attributes enclosed in single quotes.
    1415     #
    1416         $text = $this->encodeAmpsAndAngles($text);
    1417         $text = str_replace('"', '&quot;', $text);
     1404                $grafs[ $key ] = $graf;
     1405            }
     1406        }
     1407
     1408        return implode( "\n\n", $grafs );
     1409    }
     1410
     1411    function encodeAttribute( $text ) {
     1412        #
     1413        # Encode text for a double-quoted HTML attribute. This function
     1414        # is *not* suitable for attributes enclosed in single quotes.
     1415        #
     1416        $text = $this->encodeAmpsAndAngles( $text );
     1417        $text = str_replace( '"', '&quot;', $text );
     1418
    14181419        return $text;
    14191420    }
    1420    
    1421    
    1422     function encodeAmpsAndAngles($text) {
    1423     #
    1424     # Smart processing for ampersands and angle brackets that need to
    1425     # be encoded. Valid character entities are left alone unless the
    1426     # no-entities mode is set.
    1427     #
    1428         if ($this->no_entities) {
    1429             $text = str_replace('&', '&amp;', $text);
     1421
     1422    function encodeAmpsAndAngles( $text ) {
     1423        #
     1424        # Smart processing for ampersands and angle brackets that need to
     1425        # be encoded. Valid character entities are left alone unless the
     1426        # no-entities mode is set.
     1427        #
     1428        if ( $this->no_entities ) {
     1429            $text = str_replace( '&', '&amp;', $text );
    14301430        } else {
    14311431            # Ampersand-encoding based entirely on Nat Irons's Amputator
    14321432            # MT plugin: <http://bumppo.net/projects/amputator/>
    1433             $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
    1434                                 '&amp;', $text);;
     1433            $text = preg_replace( '/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
     1434                '&amp;', $text );;
    14351435        }
    14361436        # Encode remaining <'s
    1437         $text = str_replace('<', '&lt;', $text);
     1437        $text = str_replace( '<', '&lt;', $text );
    14381438
    14391439        return $text;
    14401440    }
    14411441
    1442 
    1443     function doAutoLinks($text) {
    1444         $text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i',
    1445             array(&$this, '_doAutoLinks_url_callback'), $text);
     1442    function doAutoLinks( $text ) {
     1443        $text = preg_replace_callback( '{<((https?|ftp|dict):[^\'">\s]+)>}i',
     1444            array( &$this, '_doAutoLinks_url_callback' ), $text );
    14461445
    14471446        # Email addresses: <address@domain.foo>
    1448         $text = preg_replace_callback('{
     1447        $text = preg_replace_callback( '{
    14491448            <
    14501449            (?:mailto:)?
     
    14641463            >
    14651464            }xi',
    1466             array(&$this, '_doAutoLinks_email_callback'), $text);
     1465            array( &$this, '_doAutoLinks_email_callback' ), $text );
    14671466
    14681467        return $text;
    14691468    }
    1470     function _doAutoLinks_url_callback($matches) {
    1471         $url = $this->encodeAttribute($matches[1]);
     1469
     1470    function _doAutoLinks_url_callback( $matches ) {
     1471        $url  = $this->encodeAttribute( $matches[1] );
    14721472        $link = "<a href=\"$url\">$url</a>";
    1473         return $this->hashPart($link);
    1474     }
    1475     function _doAutoLinks_email_callback($matches) {
     1473
     1474        return $this->hashPart( $link );
     1475    }
     1476
     1477    function _doAutoLinks_email_callback( $matches ) {
    14761478        $address = $matches[1];
    1477         $link = $this->encodeEmailAddress($address);
    1478         return $this->hashPart($link);
    1479     }
    1480 
    1481 
    1482     function encodeEmailAddress($addr) {
    1483     #
    1484     #   Input: an email address, e.g. "foo@example.com"
    1485     #
    1486     #   Output: the email address as a mailto link, with each character
    1487     #       of the address encoded as either a decimal or hex entity, in
    1488     #       the hopes of foiling most address harvesting spam bots. E.g.:
    1489     #
    1490     #     <p><a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#58;&#x66;o&#111;
    1491     #        &#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;&#101;&#46;&#x63;&#111;
    1492     #        &#x6d;">&#x66;o&#111;&#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;
    1493     #        &#101;&#46;&#x63;&#111;&#x6d;</a></p>
    1494     #
    1495     #   Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
    1496     #   With some optimizations by Milian Wolff.
    1497     #
    1498         $addr = "mailto:" . $addr;
    1499         $chars = preg_split('/(?<!^)(?!$)/', $addr);
    1500         $seed = (int)abs(crc32($addr) / strlen($addr)); # Deterministic seed.
    1501        
    1502         foreach ($chars as $key => $char) {
    1503             $ord = ord($char);
     1479        $link    = $this->encodeEmailAddress( $address );
     1480
     1481        return $this->hashPart( $link );
     1482    }
     1483
     1484    function encodeEmailAddress( $addr ) {
     1485        #
     1486        #   Input: an email address, e.g. "foo@example.com"
     1487        #
     1488        #   Output: the email address as a mailto link, with each character
     1489        #       of the address encoded as either a decimal or hex entity, in
     1490        #       the hopes of foiling most address harvesting spam bots. E.g.:
     1491        #
     1492        #     <p><a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#58;&#x66;o&#111;
     1493        #        &#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;&#101;&#46;&#x63;&#111;
     1494        #        &#x6d;">&#x66;o&#111;&#x40;&#101;&#x78;&#97;&#x6d;&#112;&#x6c;
     1495        #        &#101;&#46;&#x63;&#111;&#x6d;</a></p>
     1496        #
     1497        #   Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
     1498        #   With some optimizations by Milian Wolff.
     1499        #
     1500        $addr  = "mailto:" . $addr;
     1501        $chars = preg_split( '/(?<!^)(?!$)/', $addr );
     1502        $seed  = (int) abs( crc32( $addr ) / strlen( $addr ) ); # Deterministic seed.
     1503
     1504        foreach ( $chars as $key => $char ) {
     1505            $ord = ord( $char );
    15041506            # Ignore non-ascii chars.
    1505             if ($ord < 128) {
    1506                 $r = ($seed * (1 + $key)) % 100; # Pseudo-random function.
     1507            if ( $ord < 128 ) {
     1508                $r = ( $seed * ( 1 + $key ) ) % 100; # Pseudo-random function.
    15071509                # roughly 10% raw, 45% hex, 45% dec
    15081510                # '@' *must* be encoded. I insist.
    1509                 if ($r > 90 && $char != '@') /* do nothing */;
    1510                 else if ($r < 45) $chars[$key] = '&#x'.dechex($ord).';';
    1511                 else              $chars[$key] = '&#'.$ord.';';
    1512             }
    1513         }
    1514        
    1515         $addr = implode('', $chars);
    1516         $text = implode('', array_slice($chars, 7)); # text without `mailto:`
     1511                if ( $r > 90 && $char != '@' ) /* do nothing */ {
     1512                    ;
     1513                } else if ( $r < 45 ) {
     1514                    $chars[ $key ] = '&#x' . dechex( $ord ) . ';';
     1515                } else {
     1516                    $chars[ $key ] = '&#' . $ord . ';';
     1517                }
     1518            }
     1519        }
     1520
     1521        $addr = implode( '', $chars );
     1522        $text = implode( '', array_slice( $chars, 7 ) ); # text without `mailto:`
    15171523        $addr = "<a href=\"$addr\">$text</a>";
    15181524
     
    15201526    }
    15211527
    1522 
    1523     function parseSpan($str) {
    1524     #
    1525     # Take the string $str and parse it into tokens, hashing embeded HTML,
    1526     # escaped characters and handling code spans.
    1527     #
     1528    function parseSpan( $str ) {
     1529        #
     1530        # Take the string $str and parse it into tokens, hashing embeded HTML,
     1531        # escaped characters and handling code spans.
     1532        #
    15281533        $output = '';
    1529        
     1534
    15301535        $span_re = '{
    15311536                (
    1532                     \\\\'.$this->escape_chars_re.'
     1537                    \\\\' . $this->escape_chars_re . '
    15331538                |
    15341539                    (?<![`\\\\])
    15351540                    `+                      # code span marker
    1536             '.( $this->no_markup ? '' : '
     1541            ' . ( $this->no_markup ? '' : '
    15371542                |
    15381543                    <!--    .*?     -->     # comment
     
    15461551                    )?
    15471552                    >
    1548             ').'
     1553            ' ) . '
    15491554                )
    15501555                }xs';
    15511556
    1552         while (1) {
     1557        while ( 1 ) {
    15531558            #
    1554             # Each loop iteration seach for either the next tag, the next 
    1555             # openning code span marker, or the next escaped character. 
     1559            # Each loop iteration seach for either the next tag, the next
     1560            # openning code span marker, or the next escaped character.
    15561561            # Each token is then passed to handleSpanToken.
    15571562            #
    1558             $parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
    1559            
     1563            $parts = preg_split( $span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE );
     1564
    15601565            # Create token from text preceding tag.
    1561             if ($parts[0] != "") {
     1566            if ( $parts[0] != "" ) {
    15621567                $output .= $parts[0];
    15631568            }
    1564            
     1569
    15651570            # Check if we reach the end.
    1566             if (isset($parts[1])) {
    1567                 $output .= $this->handleSpanToken($parts[1], $parts[2]);
     1571            if ( isset( $parts[1] ) ) {
     1572                $output .= $this->handleSpanToken( $parts[1], $parts[2] );
    15681573                $str = $parts[2];
    1569             }
    1570             else {
     1574            } else {
    15711575                break;
    15721576            }
    15731577        }
    1574        
     1578
    15751579        return $output;
    15761580    }
    1577    
    1578    
    1579     function handleSpanToken($token, &$str) {
    1580     #
    1581     # Handle $token provided by parseSpan by determining its nature and
    1582     # returning the corresponding value that should replace it.
    1583     #
    1584         switch ($token{0}) {
     1581
     1582    function handleSpanToken( $token, &$str ) {
     1583        #
     1584        # Handle $token provided by parseSpan by determining its nature and
     1585        # returning the corresponding value that should replace it.
     1586        #
     1587        switch ( $token{0} ) {
    15851588            case "\\":
    1586                 return $this->hashPart("&#". ord($token{1}). ";");
     1589                return $this->hashPart( "&#" . ord( $token{1} ) . ";" );
    15871590            case "`":
    15881591                # Search for end marker in remaining text.
    1589                 if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
    1590                     $str, $matches))
    1591                 {
    1592                     $str = $matches[2];
    1593                     $codespan = $this->makeCodeSpan($matches[1]);
    1594                     return $this->hashPart($codespan);
     1592                if ( preg_match( '/^(.*?[^`])' . preg_quote( $token ) . '(?!`)(.*)$/sm',
     1593                    $str, $matches ) ) {
     1594                    $str      = $matches[2];
     1595                    $codespan = $this->makeCodeSpan( $matches[1] );
     1596
     1597                    return $this->hashPart( $codespan );
    15951598                }
     1599
    15961600                return $token; // return as text since no ending marker found.
    15971601            default:
    1598                 return $this->hashPart($token);
    1599         }
    1600     }
    1601 
    1602 
    1603     function outdent($text) {
    1604     #
    1605     # Remove one level of line-leading tabs or spaces
    1606     #
    1607         return preg_replace('/^(\t|[ ]{1,'.$this->tab_width.'})/m', '', $text);
    1608     }
    1609 
    1610 
    1611     # String length function for detab. `_initDetab` will create a function to
     1602                return $this->hashPart( $token );
     1603        }
     1604    }
     1605
     1606    function outdent( $text ) {
     1607        #
     1608        # Remove one level of line-leading tabs or spaces
     1609        #
     1610        return preg_replace( '/^(\t|[ ]{1,' . $this->tab_width . '})/m', '', $text );
     1611    }
     1612
     1613
     1614    # String length function for detab. `_initDetab` will create a function to
    16121615    # hanlde UTF-8 if the default function does not exist.
    16131616    var $utf8_strlen = 'mb_strlen';
    1614    
    1615     function detab($text) {
    1616     #
    1617     # Replace tabs with the appropriate amount of space.
    1618     #
     1617
     1618    function detab( $text ) {
     1619        #
     1620        # Replace tabs with the appropriate amount of space.
     1621        #
    16191622        # For each line we separate the line in blocks delemited by
    1620         # tab characters. Then we reconstruct every line by adding the 
     1623        # tab characters. Then we reconstruct every line by adding the
    16211624        # appropriate number of space between each blocks.
    1622        
    1623         $text = preg_replace_callback('/^.*\t.*$/m',
    1624             array(&$this, '_detab_callback'), $text);
     1625
     1626        $text = preg_replace_callback( '/^.*\t.*$/m',
     1627            array( &$this, '_detab_callback' ), $text );
    16251628
    16261629        return $text;
    16271630    }
    1628     function _detab_callback($matches) {
    1629         $line = $matches[0];
     1631
     1632    function _detab_callback( $matches ) {
     1633        $line   = $matches[0];
    16301634        $strlen = $this->utf8_strlen; # strlen function for UTF-8.
    1631        
     1635
    16321636        # Split in blocks.
    1633         $blocks = explode("\t", $line);
     1637        $blocks = explode( "\t", $line );
    16341638        # Add each blocks to the line.
    16351639        $line = $blocks[0];
    1636         unset($blocks[0]); # Do not add first block twice.
    1637         foreach ($blocks as $block) {
     1640        unset( $blocks[0] ); # Do not add first block twice.
     1641        foreach ( $blocks as $block ) {
    16381642            # Calculate amount of space, insert spaces, insert block.
    1639             $amount = $this->tab_width -
    1640                 $strlen($line, 'UTF-8') % $this->tab_width;
    1641             $line .= str_repeat(" ", $amount) . $block;
    1642         }
     1643            $amount = $this->tab_width -
     1644                      $strlen( $line, 'UTF-8' ) % $this->tab_width;
     1645            $line .= str_repeat( " ", $amount ) . $block;
     1646        }
     1647
    16431648        return $line;
    16441649    }
     1650
    16451651    function _initDetab() {
    1646     #
    1647     # Check for the availability of the function in the `utf8_strlen` property
    1648     # (initially `mb_strlen`). If the function is not available, create a
    1649     # function that will loosely count the number of UTF-8 characters with a
    1650     # regular expression.
    1651     #
    1652         if (function_exists($this->utf8_strlen)) return;
    1653         $this->utf8_strlen = create_function('$text', 'return preg_match_all(
    1654             "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
    1655             $text, $m);');
    1656     }
    1657 
    1658 
    1659     function unhash($text) {
    1660     #
    1661     # Swap back in all the tags hashed by _HashHTMLBlocks.
    1662     #
    1663         return preg_replace_callback('/(.)\x1A[0-9]+\1/',
    1664             array(&$this, '_unhash_callback'), $text);
    1665     }
    1666     function _unhash_callback($matches) {
    1667         return $this->html_hashes[$matches[0]];
    1668     }
    1669 
     1652        #
     1653        # Check for the availability of the function in the `utf8_strlen` property
     1654        # (initially `mb_strlen`). If the function is not available, create a
     1655        # function that will loosely count the number of UTF-8 characters with a
     1656        # regular expression.
     1657        #
     1658        if ( function_exists( $this->utf8_strlen ) ) {
     1659            return;
     1660        }
     1661        $this->utf8_strlen = create_function( '$text', 'return preg_match_all(
     1662            "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
     1663            $text, $m);' );
     1664    }
     1665
     1666    function unhash( $text ) {
     1667        #
     1668        # Swap back in all the tags hashed by _HashHTMLBlocks.
     1669        #
     1670        return preg_replace_callback( '/(.)\x1A[0-9]+\1/',
     1671            array( &$this, '_unhash_callback' ), $text );
     1672    }
     1673
     1674    function _unhash_callback( $matches ) {
     1675        return $this->html_hashes[ $matches[0] ];
     1676    }
    16701677}
    1671 
    16721678
    16731679#
     
    16761682
    16771683class MarkdownExtra_Parser extends Markdown_Parser {
    1678 
    16791684    # Prefix for footnote ids.
    16801685    var $fn_id_prefix = "";
    1681    
    16821686    # Optional title attribute for footnote links and backlinks.
    16831687    var $fn_link_title = MARKDOWN_FN_LINK_TITLE;
    16841688    var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE;
    1685    
    16861689    # Optional class attribute for footnote links and backlinks.
    16871690    var $fn_link_class = MARKDOWN_FN_LINK_CLASS;
    16881691    var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS;
    1689    
    16901692    # Predefined abbreviations.
    16911693    var $predef_abbr = array();
    16921694
    1693 
    16941695    function MarkdownExtra_Parser() {
    1695     #
    1696     # Constructor function. Initialize the parser object.
    1697     #
    1698         # Add extra escapable characters before parent constructor 
     1696        #
     1697        # Constructor function. Initialize the parser object.
     1698        #
     1699        # Add extra escapable characters before parent constructor
    16991700        # initialize the table.
    17001701        $this->escape_chars .= ':|';
    1701        
    1702         # Insert extra document, block, and span transformations. 
     1702
     1703        # Insert extra document, block, and span transformations.
    17031704        # Parent constructor will do the sorting.
    17041705        $this->document_gamut += array(
     
    17071708            "stripAbbreviations" => 25,
    17081709            "appendFootnotes"    => 50,
    1709             );
     1710        );
    17101711        $this->block_gamut += array(
    17111712            "doFencedCodeBlocks" => 5,
    17121713            "doTables"           => 15,
    17131714            "doDefLists"         => 45,
    1714             );
     1715        );
    17151716        $this->span_gamut += array(
    1716             "doFootnotes"        => 5,
    1717             "doAbbreviations"    => 70,
    1718             );
    1719        
     1717            "doFootnotes"     => 5,
     1718            "doAbbreviations" => 70,
     1719        );
     1720
    17201721        parent::Markdown_Parser();
    17211722    }
    1722    
    1723    
     1723
    17241724    # Extra variables used during extra transformations.
    17251725    var $footnotes = array();
     
    17271727    var $abbr_desciptions = array();
    17281728    var $abbr_word_re = '';
    1729    
    17301729    # Give the current footnote number.
    17311730    var $footnote_counter = 1;
    1732    
    1733    
     1731
    17341732    function setup() {
    1735     #
    1736     # Setting up Extra-specific variables.
    1737     #
     1733        #
     1734        # Setting up Extra-specific variables.
     1735        #
    17381736        parent::setup();
    1739        
    1740         $this->footnotes = array();
     1737
     1738        $this->footnotes         = array();
    17411739        $this->footnotes_ordered = array();
    1742         $this->abbr_desciptions = array();
    1743         $this->abbr_word_re = '';
    1744         $this->footnote_counter = 1;
    1745        
    1746         foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
    1747             if ($this->abbr_word_re)
     1740        $this->abbr_desciptions  = array();
     1741        $this->abbr_word_re      = '';
     1742        $this->footnote_counter  = 1;
     1743
     1744        foreach ( $this->predef_abbr as $abbr_word => $abbr_desc ) {
     1745            if ( $this->abbr_word_re ) {
    17481746                $this->abbr_word_re .= '|';
    1749             $this->abbr_word_re .= preg_quote($abbr_word);
    1750             $this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
    1751         }
    1752     }
    1753    
     1747            }
     1748            $this->abbr_word_re .= preg_quote( $abbr_word );
     1749            $this->abbr_desciptions[ $abbr_word ] = trim( $abbr_desc );
     1750        }
     1751    }
     1752
    17541753    function teardown() {
    1755     #
    1756     # Clearing Extra-specific variables.
    1757     #
    1758         $this->footnotes = array();
     1754        #
     1755        # Clearing Extra-specific variables.
     1756        #
     1757        $this->footnotes         = array();
    17591758        $this->footnotes_ordered = array();
    1760         $this->abbr_desciptions = array();
    1761         $this->abbr_word_re = '';
    1762        
     1759        $this->abbr_desciptions  = array();
     1760        $this->abbr_word_re      = '';
     1761
    17631762        parent::teardown();
    17641763    }
    1765    
    1766    
     1764
     1765
    17671766    ### HTML Block Parser ###
    1768    
     1767
    17691768    # Tags that are always treated as block tags:
    17701769    var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
    1771    
    17721770    # Tags treated as block tags only if the opening tag is alone on it's line:
    17731771    var $context_block_tags_re = 'script|noscript|math|ins|del';
    1774    
    17751772    # Tags where markdown="1" default to span mode:
    17761773    var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
    1777    
    1778     # Tags which must not have their contents modified, no matter where
     1774    # Tags which must not have their contents modified, no matter where
    17791775    # they appear:
    17801776    var $clean_tags_re = 'script|math';
    1781    
    17821777    # Tags that do not need to be closed.
    17831778    var $auto_close_tags_re = 'hr|img';
    1784    
    1785 
    1786     function hashHTMLBlocks($text) {
    1787     #
    1788     # Hashify HTML Blocks and "clean tags".
    1789     #
    1790     # We only want to do this for block-level HTML tags, such as headers,
    1791     # lists, and tables. That's because we still want to wrap <p>s around
    1792     # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
    1793     # phrase emphasis, and spans. The list of tags we're looking for is
    1794     # hard-coded.
    1795     #
    1796     # This works by calling _HashHTMLBlocks_InMarkdown, which then calls
    1797     # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1"
    1798     # attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back
    1799     #  _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
    1800     # These two functions are calling each other. It's recursive!
    1801     #
     1779
     1780    function hashHTMLBlocks( $text ) {
     1781        #
     1782        # Hashify HTML Blocks and "clean tags".
     1783        #
     1784        # We only want to do this for block-level HTML tags, such as headers,
     1785        # lists, and tables. That's because we still want to wrap <p>s around
     1786        # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
     1787        # phrase emphasis, and spans. The list of tags we're looking for is
     1788        # hard-coded.
     1789        #
     1790        # This works by calling _HashHTMLBlocks_InMarkdown, which then calls
     1791        # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1"
     1792        # attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back
     1793        #  _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
     1794        # These two functions are calling each other. It's recursive!
     1795        #
    18021796        #
    18031797        # Call the HTML-in-Markdown hasher.
    18041798        #
    1805         list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text);
    1806        
     1799        list( $text, ) = $this->_hashHTMLBlocks_inMarkdown( $text );
     1800
    18071801        return $text;
    18081802    }
    1809     function _hashHTMLBlocks_inMarkdown($text, $indent = 0,
    1810                                         $enclosing_tag_re = '', $span = false)
    1811     {
    1812     #
    1813     # Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
    1814     #
    1815     # *   $indent is the number of space to be ignored when checking for code
    1816     #     blocks. This is important because if we don't take the indent into
    1817     #     account, something like this (which looks right) won't work as expected:
    1818     #
    1819     #     <div>
    1820     #         <div markdown="1">
    1821     #         Hello World.  <-- Is this a Markdown code block or text?
    1822     #         </div>  <-- Is this a Markdown code block or a real tag?
    1823     #     <div>
    1824     #
    1825     #     If you don't like this, just don't indent the tag on which
    1826     #     you apply the markdown="1" attribute.
    1827     #
    1828     # *   If $enclosing_tag_re is not empty, stops at the first unmatched closing
    1829     #     tag with that name. Nested tags supported.
    1830     #
    1831     # *   If $span is true, text inside must treated as span. So any double
    1832     #     newline will be replaced by a single newline so that it does not create
    1833     #     paragraphs.
    1834     #
    1835     # Returns an array of that form: ( processed text , remaining text )
    1836     #
    1837         if ($text === '') return array('', '');
     1803
     1804    function _hashHTMLBlocks_inMarkdown( $text, $indent = 0, $enclosing_tag_re = '', $span = false ) {
     1805        #
     1806        # Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
     1807        #
     1808        # *   $indent is the number of space to be ignored when checking for code
     1809        #     blocks. This is important because if we don't take the indent into
     1810        #     account, something like this (which looks right) won't work as expected:
     1811        #
     1812        #     <div>
     1813        #         <div markdown="1">
     1814        #         Hello World.  <-- Is this a Markdown code block or text?
     1815        #         </div>  <-- Is this a Markdown code block or a real tag?
     1816        #     <div>
     1817        #
     1818        #     If you don't like this, just don't indent the tag on which
     1819        #     you apply the markdown="1" attribute.
     1820        #
     1821        # *   If $enclosing_tag_re is not empty, stops at the first unmatched closing
     1822        #     tag with that name. Nested tags supported.
     1823        #
     1824        # *   If $span is true, text inside must treated as span. So any double
     1825        #     newline will be replaced by a single newline so that it does not create
     1826        #     paragraphs.
     1827        #
     1828        # Returns an array of that form: ( processed text , remaining text )
     1829        #
     1830        if ( $text === '' ) {
     1831            return array( '', '' );
     1832        }
    18381833
    18391834        # Regex to check for the presense of newlines around a block tag.
    18401835        $newline_before_re = '/(?:^\n?|\n\n)*$/';
    1841         $newline_after_re =
     1836        $newline_after_re  =
    18421837            '{
    18431838                ^                       # Start of text following the tag.
     
    18451840                [ ]*\n                  # Must be followed by newline.
    18461841            }xs';
    1847        
     1842
    18481843        # Regex to match any tag.
    18491844        $block_tag_re =
     
    18521847                    </?                 # Any opening or closing tag.
    18531848                        (?>             # Tag name.
    1854                             '.$this->block_tags_re.'            |
    1855                             '.$this->context_block_tags_re.'    |
    1856                             '.$this->clean_tags_re.'            |
    1857                             (?!\s)'.$enclosing_tag_re.'
     1849                            ' . $this->block_tags_re . '            |
     1850                            ' . $this->context_block_tags_re . '    |
     1851                            ' . $this->clean_tags_re . '            |
     1852                            (?!\s)' . $enclosing_tag_re . '
    18581853                        )
    18591854                        (?:
     
    18751870                    # Code span marker
    18761871                    `+
    1877                 '. ( !$span ? ' # If not in span.
     1872                ' . ( ! $span ? ' # If not in span.
    18781873                |
    18791874                    # Indented code block
    18801875                    (?: ^[ ]*\n | ^ | \n[ ]*\n )
    1881                     [ ]{'.($indent+4).'}[^\n]* \n
     1876                    [ ]{' . ( $indent + 4 ) . '}[^\n]* \n
    18821877                    (?>
    1883                         (?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n
     1878                        (?: [ ]{' . ( $indent + 4 ) . '}[^\n]* | [ ]* ) \n
    18841879                    )*
    18851880                |
    18861881                    # Fenced code block marker
    18871882                    (?> ^ | \n )
    1888                     [ ]{'.($indent).'}~~~+[ ]*\n
    1889                 ' : '' ). ' # End (if not is span).
     1883                    [ ]{' . ( $indent ) . '}~~~+[ ]*\n
     1884                ' : '' ) . ' # End (if not is span).
    18901885                )
    18911886            }xs';
    18921887
    1893        
    1894         $depth = 0;     # Current depth inside the tag tree.
    1895         $parsed = "";   # Parsed text that will be returned.
     1888        $depth  = 0;        # Current depth inside the tag tree.
     1889        $parsed = "";    # Parsed text that will be returned.
    18961890
    18971891        #
     
    19031897            # Split the text using the first $tag_match pattern found.
    19041898            # Text before  pattern will be first in the array, text after
    1905             # pattern will be at the end, and between will be any catches made 
     1899            # pattern will be at the end, and between will be any catches made
    19061900            # by the pattern.
    19071901            #
    1908             $parts = preg_split($block_tag_re, $text, 2,
    1909                                 PREG_SPLIT_DELIM_CAPTURE);
    1910            
    1911             # If in Markdown span mode, add a empty-string span-level hash 
     1902            $parts = preg_split( $block_tag_re, $text, 2,
     1903                PREG_SPLIT_DELIM_CAPTURE );
     1904
     1905            # If in Markdown span mode, add a empty-string span-level hash
    19121906            # after each newline to prevent triggering any block element.
    1913             if ($span) {
    1914                 $void = $this->hashPart("", ':');
    1915                 $newline = "$void\n";
    1916                 $parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void;
    1917             }
    1918            
     1907            if ( $span ) {
     1908                $void     = $this->hashPart( "", ':' );
     1909                $newline  = "$void\n";
     1910                $parts[0] = $void . str_replace( "\n", $newline, $parts[0] ) . $void;
     1911            }
     1912
    19191913            $parsed .= $parts[0]; # Text before current tag.
    1920            
     1914
    19211915            # If end of $text has been reached. Stop loop.
    1922             if (count($parts) < 3) {
     1916            if ( count( $parts ) < 3 ) {
    19231917                $text = "";
    19241918                break;
    19251919            }
    1926            
    1927             $tag  = $parts[1]; # Tag to handle.
    1928             $text = $parts[2]; # Remaining text after current tag.
    1929             $tag_re = preg_quote($tag); # For use in a regular expression.
    1930            
     1920
     1921            $tag    = $parts[1]; # Tag to handle.
     1922            $text   = $parts[2]; # Remaining text after current tag.
     1923            $tag_re = preg_quote( $tag ); # For use in a regular expression.
     1924
    19311925            #
    19321926            # Check for: Code span marker
    19331927            #
    1934             if ($tag{0} == "`") {
     1928            if ( $tag{0} == "`" ) {
    19351929                # Find corresponding end marker.
    1936                 $tag_re = preg_quote($tag);
    1937                 if (preg_match('{^(?>.+?|\n(?!\n))*?(?<!`)'.$tag_re.'(?!`)}',
    1938                     $text, $matches))
    1939                 {
     1930                $tag_re = preg_quote( $tag );
     1931                if ( preg_match( '{^(?>.+?|\n(?!\n))*?(?<!`)' . $tag_re . '(?!`)}',
     1932                    $text, $matches ) ) {
    19401933                    # End marker found: pass text unchanged until marker.
    19411934                    $parsed .= $tag . $matches[0];
    1942                     $text = substr($text, strlen($matches[0]));
    1943                 }
    1944                 else {
     1935                    $text = substr( $text, strlen( $matches[0] ) );
     1936                } else {
    19451937                    # Unmatched marker: just skip it.
    19461938                    $parsed .= $tag;
     
    19501942            # Check for: Indented code block.
    19511943            #
    1952             else if ($tag{0} == "\n" || $tag{0} == " ") {
    1953                 # Indented code block: pass it unchanged, will be handled 
     1944            else if ( $tag{0} == "\n" || $tag{0} == " " ) {
     1945                # Indented code block: pass it unchanged, will be handled
    19541946                # later.
    19551947                $parsed .= $tag;
     
    19581950            # Check for: Fenced code block marker.
    19591951            #
    1960             else if ($tag{0} == "~") {
     1952            else if ( $tag{0} == "~" ) {
    19611953                # Fenced code block marker: find matching end marker.
    1962                 $tag_re = preg_quote(trim($tag));
    1963                 if (preg_match('{^(?>.*\n)+?'.$tag_re.' *\n}', $text,
    1964                     $matches))
    1965                 {
     1954                $tag_re = preg_quote( trim( $tag ) );
     1955                if ( preg_match( '{^(?>.*\n)+?' . $tag_re . ' *\n}', $text,
     1956                    $matches ) ) {
    19661957                    # End marker found: pass text unchanged until marker.
    19671958                    $parsed .= $tag . $matches[0];
    1968                     $text = substr($text, strlen($matches[0]));
    1969                 }
    1970                 else {
     1959                    $text = substr( $text, strlen( $matches[0] ) );
     1960                } else {
    19711961                    # No end marker: just skip it.
    19721962                    $parsed .= $tag;
     
    19751965            #
    19761966            # Check for: Opening Block level tag or
    1977             #            Opening Context Block tag (like ins and del) 
     1967            #            Opening Context Block tag (like ins and del)
    19781968            #               used as a block tag (tag is alone on it's line).
    19791969            #
    1980             else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) ||
    1981                 (   preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) &&
    1982                     preg_match($newline_before_re, $parsed) &&
    1983                     preg_match($newline_after_re, $text)    )
    1984                 )
    1985             {
     1970            else if ( preg_match( '{^<(?:' . $this->block_tags_re . ')\b}', $tag ) ||
     1971                      ( preg_match( '{^<(?:' . $this->context_block_tags_re . ')\b}', $tag ) &&
     1972                        preg_match( $newline_before_re, $parsed ) &&
     1973                        preg_match( $newline_after_re, $text ) )
     1974            ) {
    19861975                # Need to parse tag and following text using the HTML parser.
    1987                 list($block_text, $text) =
    1988                     $this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true);
    1989                
     1976                list( $block_text, $text ) =
     1977                    $this->_hashHTMLBlocks_inHTML( $tag . $text, "hashBlock", true );
     1978
    19901979                # Make sure it stays outside of any paragraph by adding newlines.
    19911980                $parsed .= "\n\n$block_text\n\n";
     
    19951984            #            HTML Comments, processing instructions.
    19961985            #
    1997             else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) ||
    1998                 $tag{1} == '!' || $tag{1} == '?')
    1999             {
     1986            else if ( preg_match( '{^<(?:' . $this->clean_tags_re . ')\b}', $tag ) ||
     1987                      $tag{1} == '!' || $tag{1} == '?'
     1988            ) {
    20001989                # Need to parse tag and following text using the HTML parser.
    20011990                # (don't check for markdown attribute)
    2002                 list($block_text, $text) =
    2003                     $this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false);
    2004                
     1991                list( $block_text, $text ) =
     1992                    $this->_hashHTMLBlocks_inHTML( $tag . $text, "hashClean", false );
     1993
    20051994                $parsed .= $block_text;
    20061995            }
     
    20081997            # Check for: Tag with same name as enclosing tag.
    20091998            #
    2010             else if ($enclosing_tag_re !== '' &&
    2011                 # Same name as enclosing tag.
    2012                 preg_match('{^</?(?:'.$enclosing_tag_re.')\b}', $tag))
    2013             {
     1999            else if ( $enclosing_tag_re !== '' &&
     2000                      # Same name as enclosing tag.
     2001                      preg_match( '{^</?(?:' . $enclosing_tag_re . ')\b}', $tag )
     2002            ) {
    20142003                #
    20152004                # Increase/decrease nested tag count.
    20162005                #
    2017                 if ($tag{1} == '/')                     $depth--;
    2018                 else if ($tag{strlen($tag)-2} != '/')   $depth++;
    2019 
    2020                 if ($depth < 0) {
     2006                if ( $tag{1} == '/' ) {
     2007                    $depth --;
     2008                } else if ( $tag{strlen( $tag ) - 2} != '/' ) {
     2009                    $depth ++;
     2010                }
     2011
     2012                if ( $depth < 0 ) {
    20212013                    #
    20222014                    # Going out of parent element. Clean up and break so we
     
    20262018                    break;
    20272019                }
    2028                
     2020
    20292021                $parsed .= $tag;
    2030             }
    2031             else {
     2022            } else {
    20322023                $parsed .= $tag;
    20332024            }
    2034         } while ($depth >= 0);
    2035        
    2036         return array($parsed, $text);
    2037     }
    2038     function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) {
    2039     #
    2040     # Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags.
    2041     #
    2042     # *   Calls $hash_method to convert any blocks.
    2043     # *   Stops when the first opening tag closes.
    2044     # *   $md_attr indicate if the use of the `markdown="1"` attribute is allowed.
    2045     #     (it is not inside clean tags)
    2046     #
    2047     # Returns an array of that form: ( processed text , remaining text )
    2048     #
    2049         if ($text === '') return array('', '');
    2050        
     2025        } while ( $depth >= 0 );
     2026
     2027        return array( $parsed, $text );
     2028    }
     2029
     2030    function _hashHTMLBlocks_inHTML( $text, $hash_method, $md_attr ) {
     2031        #
     2032        # Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags.
     2033        #
     2034        # *   Calls $hash_method to convert any blocks.
     2035        # *   Stops when the first opening tag closes.
     2036        # *   $md_attr indicate if the use of the `markdown="1"` attribute is allowed.
     2037        #     (it is not inside clean tags)
     2038        #
     2039        # Returns an array of that form: ( processed text , remaining text )
     2040        #
     2041        if ( $text === '' ) {
     2042            return array( '', '' );
     2043        }
     2044
    20512045        # Regex to match `markdown` attribute inside of a tag.
    20522046        $markdown_attr_re = '
     
    20562050                \s*=\s*
    20572051                (?>
    2058                     (["\'])     # $1: quote delimiter       
     2052                    (["\'])     # $1: quote delimiter
    20592053                    (.*?)       # $2: attribute value
    2060                     \1          # matching delimiter   
     2054                    \1          # matching delimiter
    20612055                |
    20622056                    ([^\s>]*)   # $3: unquoted attribute value
     
    20642058                ()              # $4: make $3 always defined (avoid warnings)
    20652059            }xs';
    2066        
     2060
    20672061        # Regex to match any tag.
    20682062        $tag_re = '{
     
    20872081                )
    20882082            }xs';
    2089        
    2090         $original_text = $text;     # Save original text in case of faliure.
    2091        
    2092         $depth      = 0;    # Current depth inside the tag tree.
    2093         $block_text = "";   # Temporary text holder for current text.
    2094         $parsed     = "";   # Parsed text that will be returned.
     2083
     2084        $original_text = $text;        # Save original text in case of faliure.
     2085
     2086        $depth      = 0;    # Current depth inside the tag tree.
     2087        $block_text = "";    # Temporary text holder for current text.
     2088        $parsed     = "";    # Parsed text that will be returned.
    20952089
    20962090        #
     
    20982092        # (This pattern makes $base_tag_name_re safe without quoting.)
    20992093        #
    2100         if (preg_match('/^<([\w:$]*)\b/', $text, $matches))
     2094        if ( preg_match( '/^<([\w:$]*)\b/', $text, $matches ) ) {
    21012095            $base_tag_name_re = $matches[1];
     2096        }
    21022097
    21032098        #
     
    21082103            # Split the text using the first $tag_match pattern found.
    21092104            # Text before  pattern will be first in the array, text after
    2110             # pattern will be at the end, and between will be any catches made 
     2105            # pattern will be at the end, and between will be any catches made
    21112106            # by the pattern.
    21122107            #
    2113             $parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
    2114            
    2115             if (count($parts) < 3) {
     2108            $parts = preg_split( $tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE );
     2109
     2110            if ( count( $parts ) < 3 ) {
    21162111                #
    21172112                # End of $text reached with unbalenced tag(s).
    21182113                # In that case, we return original text unchanged and pass the
    2119                 # first character as filtered to prevent an infinite loop in the 
     2114                # first character as filtered to prevent an infinite loop in the
    21202115                # parent function.
    21212116                #
    2122                 return array($original_text{0}, substr($original_text, 1));
    2123             }
    2124            
     2117                return array( $original_text{0}, substr( $original_text, 1 ) );
     2118            }
     2119
    21252120            $block_text .= $parts[0]; # Text before current tag.
    2126             $tag         = $parts[1]; # Tag to handle.
    2127             $text        = $parts[2]; # Remaining text after current tag.
    2128            
     2121            $tag  = $parts[1]; # Tag to handle.
     2122            $text = $parts[2]; # Remaining text after current tag.
     2123
    21292124            #
    21302125            # Check for: Auto-close tag (like <hr/>)
    21312126            #            Comments and Processing Instructions.
    21322127            #
    2133             if (preg_match('{^</?(?:'.$this->auto_close_tags_re.')\b}', $tag) ||
    2134                 $tag{1} == '!' || $tag{1} == '?')
    2135             {
     2128            if ( preg_match( '{^</?(?:' . $this->auto_close_tags_re . ')\b}', $tag ) ||
     2129                 $tag{1} == '!' || $tag{1} == '?'
     2130            ) {
    21362131                # Just add the tag to the block as if it was text.
    21372132                $block_text .= $tag;
    2138             }
    2139             else {
     2133            } else {
    21402134                #
    21412135                # Increase/decrease nested tag count. Only do so if
    21422136                # the tag's name match base tag's.
    21432137                #
    2144                 if (preg_match('{^</?'.$base_tag_name_re.'\b}', $tag)) {
    2145                     if ($tag{1} == '/')                     $depth--;
    2146                     else if ($tag{strlen($tag)-2} != '/')   $depth++;
     2138                if ( preg_match( '{^</?' . $base_tag_name_re . '\b}', $tag ) ) {
     2139                    if ( $tag{1} == '/' ) {
     2140                        $depth --;
     2141                    } else if ( $tag{strlen( $tag ) - 2} != '/' ) {
     2142                        $depth ++;
     2143                    }
    21472144                }
    2148                
     2145
    21492146                #
    21502147                # Check for `markdown="1"` attribute and handle it.
    21512148                #
    2152                 if ($md_attr &&
    2153                     preg_match($markdown_attr_re, $tag, $attr_m) &&
    2154                     preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3]))
    2155                 {
     2149                if ( $md_attr &&
     2150                     preg_match( $markdown_attr_re, $tag, $attr_m ) &&
     2151                     preg_match( '/^1|block|span$/', $attr_m[2] . $attr_m[3] )
     2152                ) {
    21562153                    # Remove `markdown` attribute from opening tag.
    2157                     $tag = preg_replace($markdown_attr_re, '', $tag);
    2158                    
     2154                    $tag = preg_replace( $markdown_attr_re, '', $tag );
     2155
    21592156                    # Check if text inside this tag must be parsed in span mode.
    21602157                    $this->mode = $attr_m[2] . $attr_m[3];
    2161                     $span_mode = $this->mode == 'span' || $this->mode != 'block' &&
    2162                         preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag);
    2163                    
     2158                    $span_mode  = $this->mode == 'span' || $this->mode != 'block' &&
     2159                                                           preg_match( '{^<(?:' . $this->contain_span_tags_re . ')\b}', $tag );
     2160
    21642161                    # Calculate indent before tag.
    2165                     if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
     2162                    if ( preg_match( '/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches ) ) {
    21662163                        $strlen = $this->utf8_strlen;
    2167                         $indent = $strlen($matches[1], 'UTF-8');
     2164                        $indent = $strlen( $matches[1], 'UTF-8' );
    21682165                    } else {
    21692166                        $indent = 0;
    21702167                    }
    2171                    
     2168
    21722169                    # End preceding block with this tag.
    21732170                    $block_text .= $tag;
    2174                     $parsed .= $this->$hash_method($block_text);
    2175                    
     2171                    $parsed .= $this->$hash_method( $block_text );
     2172
    21762173                    # Get enclosing tag name for the ParseMarkdown function.
    21772174                    # (This pattern makes $tag_name_re safe without quoting.)
    2178                     preg_match('/^<([\w:$]*)\b/', $tag, $matches);
     2175                    preg_match( '/^<([\w:$]*)\b/', $tag, $matches );
    21792176                    $tag_name_re = $matches[1];
    2180                    
     2177
    21812178                    # Parse the content using the HTML-in-Markdown parser.
    2182                     list ($block_text, $text)
    2183                         = $this->_hashHTMLBlocks_inMarkdown($text, $indent,
    2184                             $tag_name_re, $span_mode);
    2185                    
     2179                    list ( $block_text, $text )
     2180                        = $this->_hashHTMLBlocks_inMarkdown( $text, $indent,
     2181                        $tag_name_re, $span_mode );
     2182
    21862183                    # Outdent markdown text.
    2187                     if ($indent > 0) {
    2188                         $block_text = preg_replace("/^[ ]{1,$indent}/m", "",
    2189                                                     $block_text);
     2184                    if ( $indent > 0 ) {
     2185                        $block_text = preg_replace( "/^[ ]{1,$indent}/m", "",
     2186                            $block_text );
    21902187                    }
    2191                    
     2188
    21922189                    # Append tag content to parsed text.
    2193                     if (!$span_mode)    $parsed .= "\n\n$block_text\n\n";
    2194                     else                $parsed .= "$block_text";
    2195                    
     2190                    if ( ! $span_mode ) {
     2191                        $parsed .= "\n\n$block_text\n\n";
     2192                    } else {
     2193                        $parsed .= "$block_text";
     2194                    }
     2195
    21962196                    # Start over a new block.
    21972197                    $block_text = "";
     2198                } else {
     2199                    $block_text .= $tag;
    21982200                }
    2199                 else $block_text .= $tag;
    2200             }
    2201            
    2202         } while ($depth > 0);
    2203        
     2201            }
     2202        } while ( $depth > 0 );
     2203
    22042204        #
    22052205        # Hash last block text that wasn't processed inside the loop.
    22062206        #
    2207         $parsed .= $this->$hash_method($block_text);
    2208        
    2209         return array($parsed, $text);
    2210     }
    2211 
    2212 
    2213     function hashClean($text) {
    2214     #
    2215     # Called whenever a tag must be hashed when a function insert a "clean" tag
    2216     # in $text, it pass through this function and is automaticaly escaped,
    2217     # blocking invalid nested overlap.
    2218     #
    2219         return $this->hashPart($text, 'C');
    2220     }
    2221 
    2222 
    2223     function doHeaders($text) {
    2224     #
    2225     # Redefined to add id attribute support.
    2226     #
     2207        $parsed .= $this->$hash_method( $block_text );
     2208
     2209        return array( $parsed, $text );
     2210    }
     2211
     2212    function hashClean( $text ) {
     2213        #
     2214        # Called whenever a tag must be hashed when a function insert a "clean" tag
     2215        # in $text, it pass through this function and is automaticaly escaped,
     2216        # blocking invalid nested overlap.
     2217        #
     2218        return $this->hashPart( $text, 'C' );
     2219    }
     2220
     2221    function doHeaders( $text ) {
     2222        #
     2223        # Redefined to add id attribute support.
     2224        #
    22272225        # Setext-style headers:
    22282226        #     Header 1  {#header1}
    22292227        #     ========
    2230         # 
     2228        #
    22312229        #     Header 2  {#header2}
    22322230        #     --------
     
    22382236                [ ]*\n(=+|-+)[ ]*\n+                # $3: Header footer
    22392237            }mx',
    2240             array(&$this, '_doHeaders_callback_setext'), $text);
     2238            array( &$this, '_doHeaders_callback_setext' ), $text );
    22412239
    22422240        # atx-style headers:
     
    22472245        #   ###### Header 6   {#header2}
    22482246        #
    2249         $text = preg_replace_callback('{
     2247        $text = preg_replace_callback( '{
    22502248                ^(\#{1,6})  # $1 = string of #\'s
    22512249                [ ]*
     
    22572255                \n+
    22582256            }xm',
    2259             array(&$this, '_doHeaders_callback_atx'), $text);
     2257            array( &$this, '_doHeaders_callback_atx' ), $text );
    22602258
    22612259        return $text;
    22622260    }
    2263     function _doHeaders_attr($attr) {
    2264         if (empty($attr))  return "";
     2261
     2262    function _doHeaders_attr( $attr ) {
     2263        if ( empty( $attr ) ) {
     2264            return "";
     2265        }
     2266
    22652267        return " id=\"$attr\"";
    22662268    }
    2267     function _doHeaders_callback_setext($matches) {
    2268         if ($matches[3] == '-' && preg_match('{^- }', $matches[1]))
     2269
     2270    function _doHeaders_callback_setext( $matches ) {
     2271        if ( $matches[3] == '-' && preg_match( '{^- }', $matches[1] ) ) {
    22692272            return $matches[0];
     2273        }
    22702274        $level = $matches[3]{0} == '=' ? 1 : 2;
    2271         $attr  = $this->_doHeaders_attr($id =& $matches[2]);
    2272         $block = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>";
    2273         return "\n" . $this->hashBlock($block) . "\n\n";
    2274     }
    2275     function _doHeaders_callback_atx($matches) {
    2276         $level = strlen($matches[1]);
    2277         $attr  = $this->_doHeaders_attr($id =& $matches[3]);
    2278         $block = "<h$level$attr>".$this->runSpanGamut($matches[2])."</h$level>";
    2279         return "\n" . $this->hashBlock($block) . "\n\n";
    2280     }
    2281 
    2282 
    2283     function doTables($text) {
    2284     #
    2285     # Form HTML tables.
    2286     #
     2275        $attr  = $this->_doHeaders_attr( $id =& $matches[2] );
     2276        $block = "<h$level$attr>" . $this->runSpanGamut( $matches[1] ) . "</h$level>";
     2277
     2278        return "\n" . $this->hashBlock( $block ) . "\n\n";
     2279    }
     2280
     2281    function _doHeaders_callback_atx( $matches ) {
     2282        $level = strlen( $matches[1] );
     2283        $attr  = $this->_doHeaders_attr( $id =& $matches[3] );
     2284        $block = "<h$level$attr>" . $this->runSpanGamut( $matches[2] ) . "</h$level>";
     2285
     2286        return "\n" . $this->hashBlock( $block ) . "\n\n";
     2287    }
     2288
     2289    function doTables( $text ) {
     2290        #
     2291        # Form HTML tables.
     2292        #
    22872293        $less_than_tab = $this->tab_width - 1;
    22882294        #
     
    22942300        #   | Cell 3   | Cell 4
    22952301        #
    2296         $text = preg_replace_callback('
     2302        $text = preg_replace_callback( '
    22972303            {
    22982304                ^                           # Start of a line
    2299                 [ ]{0,'.$less_than_tab.'}   # Allowed whitespace.
     2305                [ ]{0,' . $less_than_tab . '}   # Allowed whitespace.
    23002306                [|]                         # Optional leading pipe (present)
    23012307                (.+) \n                     # $1: Header row (at least one pipe)
    2302                
    2303                 [ ]{0,'.$less_than_tab.'}   # Allowed whitespace.
     2308
     2309                [ ]{0,' . $less_than_tab . '}   # Allowed whitespace.
    23042310                [|] ([ ]*[-:]+[-| :]*) \n   # $2: Header underline
    2305                
     2311
    23062312                (                           # $3: Cells
    23072313                    (?>
     
    23122318                (?=\n|\Z)                   # Stop at final double newline.
    23132319            }xm',
    2314             array(&$this, '_doTable_leadingPipe_callback'), $text);
    2315        
     2320            array( &$this, '_doTable_leadingPipe_callback' ), $text );
     2321
    23162322        #
    23172323        # Find tables without leading pipe.
     
    23222328        #   Cell 3   | Cell 4
    23232329        #
    2324         $text = preg_replace_callback('
     2330        $text = preg_replace_callback( '
    23252331            {
    23262332                ^                           # Start of a line
    2327                 [ ]{0,'.$less_than_tab.'}   # Allowed whitespace.
     2333                [ ]{0,' . $less_than_tab . '}   # Allowed whitespace.
    23282334                (\S.*[|].*) \n              # $1: Header row (at least one pipe)
    2329                
    2330                 [ ]{0,'.$less_than_tab.'}   # Allowed whitespace.
     2335
     2336                [ ]{0,' . $less_than_tab . '}   # Allowed whitespace.
    23312337                ([-:]+[ ]*[|][-| :]*) \n    # $2: Header underline
    2332                
     2338
    23332339                (                           # $3: Cells
    23342340                    (?>
     
    23382344                (?=\n|\Z)                   # Stop at final double newline.
    23392345            }xm',
    2340             array(&$this, '_DoTable_callback'), $text);
     2346            array( &$this, '_DoTable_callback' ), $text );
    23412347
    23422348        return $text;
    23432349    }
    2344     function _doTable_leadingPipe_callback($matches) {
    2345         $head       = $matches[1];
    2346         $underline  = $matches[2];
    2347         $content    = $matches[3];
    2348        
     2350
     2351    function _doTable_leadingPipe_callback( $matches ) {
     2352        $head      = $matches[1];
     2353        $underline = $matches[2];
     2354        $content   = $matches[3];
     2355
    23492356        # Remove leading pipe for each row.
    2350         $content    = preg_replace('/^ *[|]/m', '', $content);
    2351        
    2352         return $this->_doTable_callback(array($matches[0], $head, $underline, $content));
    2353     }
    2354     function _doTable_callback($matches) {
    2355         $head       = $matches[1];
    2356         $underline  = $matches[2];
    2357         $content    = $matches[3];
     2357        $content = preg_replace( '/^ *[|]/m', '', $content );
     2358
     2359        return $this->_doTable_callback( array( $matches[0], $head, $underline, $content ) );
     2360    }
     2361
     2362    function _doTable_callback( $matches ) {
     2363        $head      = $matches[1];
     2364        $underline = $matches[2];
     2365        $content   = $matches[3];
    23582366
    23592367        # Remove any tailing pipes for each line.
    2360         $head       = preg_replace('/[|] *$/m', '', $head);
    2361         $underline  = preg_replace('/[|] *$/m', '', $underline);
    2362         $content    = preg_replace('/[|] *$/m', '', $content);
    2363        
     2368        $head      = preg_replace( '/[|] *$/m', '', $head );
     2369        $underline = preg_replace( '/[|] *$/m', '', $underline );
     2370        $content   = preg_replace( '/[|] *$/m', '', $content );
     2371
    23642372        # Reading alignement from header underline.
    2365         $separators = preg_split('/ *[|] */', $underline);
    2366         foreach ($separators as $n => $s) {
    2367             if (preg_match('/^ *-+: *$/', $s))      $attr[$n] = ' align="right"';
    2368             else if (preg_match('/^ *:-+: *$/', $s))$attr[$n] = ' align="center"';
    2369             else if (preg_match('/^ *:-+ *$/', $s)) $attr[$n] = ' align="left"';
    2370             else                                    $attr[$n] = '';
    2371         }
    2372        
    2373         # Parsing span elements, including code spans, character escapes,
     2373        $separators = preg_split( '/ *[|] */', $underline );
     2374        foreach ( $separators as $n => $s ) {
     2375            if ( preg_match( '/^ *-+: *$/', $s ) ) {
     2376                $attr[ $n ] = ' align="right"';
     2377            } else if ( preg_match( '/^ *:-+: *$/', $s ) ) {
     2378                $attr[ $n ] = ' align="center"';
     2379            } else if ( preg_match( '/^ *:-+ *$/', $s ) ) {
     2380                $attr[ $n ] = ' align="left"';
     2381            } else {
     2382                $attr[ $n ] = '';
     2383            }
     2384        }
     2385
     2386        # Parsing span elements, including code spans, character escapes,
    23742387        # and inline HTML tags, so that pipes inside those gets ignored.
    2375         $head       = $this->parseSpan($head);
    2376         $headers    = preg_split('/ *[|] */', $head);
    2377         $col_count  = count($headers);
    2378        
     2388        $head      = $this->parseSpan( $head );
     2389        $headers   = preg_split( '/ *[|] */', $head );
     2390        $col_count = count( $headers );
     2391
    23792392        # Write column headers.
    23802393        $text = "<table>\n";
    23812394        $text .= "<thead>\n";
    23822395        $text .= "<tr>\n";
    2383         foreach ($headers as $n => $header)
    2384             $text .= "  <th$attr[$n]>".$this->runSpanGamut(trim($header))."</th>\n";
     2396        foreach ( $headers as $n => $header ) {
     2397            $text .= "  <th$attr[$n]>" . $this->runSpanGamut( trim( $header ) ) . "</th>\n";
     2398        }
    23852399        $text .= "</tr>\n";
    23862400        $text .= "</thead>\n";
    2387        
     2401
    23882402        # Split content by row.
    2389         $rows = explode("\n", trim($content, "\n"));
    2390        
     2403        $rows = explode( "\n", trim( $content, "\n" ) );
     2404
    23912405        $text .= "<tbody>\n";
    2392         foreach ($rows as $row) {
    2393             # Parsing span elements, including code spans, character escapes, 
     2406        foreach ( $rows as $row ) {
     2407            # Parsing span elements, including code spans, character escapes,
    23942408            # and inline HTML tags, so that pipes inside those gets ignored.
    2395             $row = $this->parseSpan($row);
    2396            
     2409            $row = $this->parseSpan( $row );
     2410
    23972411            # Split row by cell.
    2398             $row_cells = preg_split('/ *[|] */', $row, $col_count);
    2399             $row_cells = array_pad($row_cells, $col_count, '');
    2400            
     2412            $row_cells = preg_split( '/ *[|] */', $row, $col_count );
     2413            $row_cells = array_pad( $row_cells, $col_count, '' );
     2414
    24012415            $text .= "<tr>\n";
    2402             foreach ($row_cells as $n => $cell)
    2403                 $text .= "  <td$attr[$n]>".$this->runSpanGamut(trim($cell))."</td>\n";
     2416            foreach ( $row_cells as $n => $cell ) {
     2417                $text .= "  <td$attr[$n]>" . $this->runSpanGamut( trim( $cell ) ) . "</td>\n";
     2418            }
    24042419            $text .= "</tr>\n";
    24052420        }
    24062421        $text .= "</tbody>\n";
    24072422        $text .= "</table>";
    2408        
    2409         return $this->hashBlock($text) . "\n";
    2410     }
    2411 
    2412    
    2413     function doDefLists($text) {
    2414     #
    2415     # Form HTML definition lists.
    2416     #
     2423
     2424        return $this->hashBlock( $text ) . "\n";
     2425    }
     2426
     2427    function doDefLists( $text ) {
     2428        #
     2429        # Form HTML definition lists.
     2430        #
    24172431        $less_than_tab = $this->tab_width - 1;
    24182432
     
    24212435            (                               # $1 = whole list
    24222436              (                             # $2
    2423                 [ ]{0,'.$less_than_tab.'}
     2437                [ ]{0,' . $less_than_tab . '}
    24242438                ((?>.*\S.*\n)+)             # $3 = defined term
    24252439                \n?
    2426                 [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
     2440                [ ]{0,' . $less_than_tab . '}:[ ]+ # colon starting definition
    24272441              )
    24282442              (?s:.+?)
     
    24332447                  (?=\S)
    24342448                  (?!                       # Negative lookahead for another term
    2435                     [ ]{0,'.$less_than_tab.'}
     2449                    [ ]{0,' . $less_than_tab . '}
    24362450                    (?: \S.*\n )+?          # defined term
    24372451                    \n?
    2438                     [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
     2452                    [ ]{0,' . $less_than_tab . '}:[ ]+ # colon starting definition
    24392453                  )
    24402454                  (?!                       # Negative lookahead for another definition
    2441                     [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
     2455                    [ ]{0,' . $less_than_tab . '}:[ ]+ # colon starting definition
    24422456                  )
    24432457              )
     
    24452459        )'; // mx
    24462460
    2447         $text = preg_replace_callback('{
     2461        $text = preg_replace_callback( '{
    24482462                (?>\A\n?|(?<=\n\n))
    2449                 '.$whole_list_re.'
     2463                ' . $whole_list_re . '
    24502464            }mx',
    2451             array(&$this, '_doDefLists_callback'), $text);
     2465            array( &$this, '_doDefLists_callback' ), $text );
    24522466
    24532467        return $text;
    24542468    }
    2455     function _doDefLists_callback($matches) {
     2469
     2470    function _doDefLists_callback( $matches ) {
    24562471        # Re-usable patterns to match list item bullets and number markers:
    24572472        $list = $matches[1];
    2458        
     2473
    24592474        # Turn double returns into triple returns, so that we can make a
    24602475        # paragraph for the last item in a list, if necessary:
    2461         $result = trim($this->processDefListItems($list));
     2476        $result = trim( $this->processDefListItems( $list ) );
    24622477        $result = "<dl>\n" . $result . "\n</dl>";
    2463         return $this->hashBlock($result) . "\n\n";
    2464     }
    2465 
    2466 
    2467     function processDefListItems($list_str) {
    2468     #
    2469     #   Process the contents of a single definition list, splitting it
    2470     #   into individual term and definition list items.
    2471     #
     2478
     2479        return $this->hashBlock( $result ) . "\n\n";
     2480    }
     2481
     2482    function processDefListItems( $list_str ) {
     2483        #
     2484        #   Process the contents of a single definition list, splitting it
     2485        #   into individual term and definition list items.
     2486        #
    24722487        $less_than_tab = $this->tab_width - 1;
    2473        
     2488
    24742489        # trim trailing blank lines:
    2475         $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
     2490        $list_str = preg_replace( "/\n{2,}\\z/", "\n", $list_str );
    24762491
    24772492        # Process definition terms.
    2478         $list_str = preg_replace_callback('{
     2493        $list_str = preg_replace_callback( '{
    24792494            (?>\A\n?|\n\n+)                 # leading line
    24802495            (                               # definition terms = $1
    2481                 [ ]{0,'.$less_than_tab.'}   # leading whitespace
    2482                 (?![:][ ]|[ ])              # negative lookahead for a definition 
     2496                [ ]{0,' . $less_than_tab . '}   # leading whitespace
     2497                (?![:][ ]|[ ])              # negative lookahead for a definition
    24832498                                            #   mark (colon) or more whitespace.
    2484                 (?> \S.* \n)+?              # actual term (not whitespace). 
    2485             )           
    2486             (?=\n?[ ]{0,3}:[ ])             # lookahead for following line feed 
     2499                (?> \S.* \n)+?              # actual term (not whitespace).
     2500            )
     2501            (?=\n?[ ]{0,3}:[ ])             # lookahead for following line feed
    24872502                                            #   with a definition mark.
    24882503            }xm',
    2489             array(&$this, '_processDefListItems_callback_dt'), $list_str);
     2504            array( &$this, '_processDefListItems_callback_dt' ), $list_str );
    24902505
    24912506        # Process actual definitions.
    2492         $list_str = preg_replace_callback('{
     2507        $list_str = preg_replace_callback( '{
    24932508            \n(\n+)?                        # leading line = $1
    24942509            (                               # marker space = $2
    2495                 [ ]{0,'.$less_than_tab.'}   # whitespace before colon
     2510                [ ]{0,' . $less_than_tab . '}   # whitespace before colon
    24962511                [:][ ]+                     # definition mark (colon)
    24972512            )
     
    24992514            (?= \n+                         # stop at next definition mark,
    25002515                (?:                         # next term or end of text
    2501                     [ ]{0,'.$less_than_tab.'} [:][ ]    |
     2516                    [ ]{0,' . $less_than_tab . '} [:][ ]    |
    25022517                    <dt> | \z
    2503                 )                       
    2504             )                   
     2518                )
     2519            )
    25052520            }xm',
    2506             array(&$this, '_processDefListItems_callback_dd'), $list_str);
     2521            array( &$this, '_processDefListItems_callback_dd' ), $list_str );
    25072522
    25082523        return $list_str;
    25092524    }
    2510     function _processDefListItems_callback_dt($matches) {
    2511         $terms = explode("\n", trim($matches[1]));
    2512         $text = '';
    2513         foreach ($terms as $term) {
    2514             $term = $this->runSpanGamut(trim($term));
     2525
     2526    function _processDefListItems_callback_dt( $matches ) {
     2527        $terms = explode( "\n", trim( $matches[1] ) );
     2528        $text  = '';
     2529        foreach ( $terms as $term ) {
     2530            $term = $this->runSpanGamut( trim( $term ) );
    25152531            $text .= "\n<dt>" . $term . "</dt>";
    25162532        }
     2533
    25172534        return $text . "\n";
    25182535    }
    2519     function _processDefListItems_callback_dd($matches) {
    2520         $leading_line   = $matches[1];
    2521         $marker_space   = $matches[2];
    2522         $def            = $matches[3];
    2523 
    2524         if ($leading_line || preg_match('/\n{2,}/', $def)) {
     2536
     2537    function _processDefListItems_callback_dd( $matches ) {
     2538        $leading_line = $matches[1];
     2539        $marker_space = $matches[2];
     2540        $def          = $matches[3];
     2541
     2542        if ( $leading_line || preg_match( '/\n{2,}/', $def ) ) {
    25252543            # Replace marker with the appropriate whitespace indentation
    2526             $def = str_repeat(' ', strlen($marker_space)) . $def;
    2527             $def = $this->runBlockGamut($this->outdent($def . "\n\n"));
    2528             $def = "\n". $def ."\n";
    2529         }
    2530         else {
    2531             $def = rtrim($def);
    2532             $def = $this->runSpanGamut($this->outdent($def));
     2544            $def = str_repeat( ' ', strlen( $marker_space ) ) . $def;
     2545            $def = $this->runBlockGamut( $this->outdent( $def . "\n\n" ) );
     2546            $def = "\n" . $def . "\n";
     2547        } else {
     2548            $def = rtrim( $def );
     2549            $def = $this->runSpanGamut( $this->outdent( $def ) );
    25332550        }
    25342551
     
    25362553    }
    25372554
    2538 
    2539     function doFencedCodeBlocks($text) {
    2540     #
    2541     # Adding the fenced code block syntax to regular Markdown:
    2542     #
    2543     # ~~~
    2544     # Code block
    2545     # ~~~
    2546     #
     2555    function doFencedCodeBlocks( $text ) {
     2556        #
     2557        # Adding the fenced code block syntax to regular Markdown:
     2558        #
     2559        # ~~~
     2560        # Code block
     2561        # ~~~
     2562        #
    25472563        $less_than_tab = $this->tab_width;
    2548        
    2549         $text = preg_replace_callback('{
     2564
     2565        $text = preg_replace_callback( '{
    25502566                (?:\n|\A)
    25512567                # 1: Opening marker
     
    25542570                )
    25552571                [ ]* \n # Whitespace and newline following marker.
    2556                
     2572
    25572573                # 2: Content
    25582574                (
     
    25622578                    )+
    25632579                )
    2564                
     2580
    25652581                # Closing marker.
    25662582                \1 [ ]* \n
    25672583            }xm',
    2568             array(&$this, '_doFencedCodeBlocks_callback'), $text);
     2584            array( &$this, '_doFencedCodeBlocks_callback' ), $text );
    25692585
    25702586        return $text;
    25712587    }
    2572     function _doFencedCodeBlocks_callback($matches) {
     2588
     2589    function _doFencedCodeBlocks_callback( $matches ) {
    25732590        $codeblock = $matches[2];
    2574         $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
    2575         $codeblock = preg_replace_callback('/^\n+/',
    2576             array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock);
     2591        $codeblock = htmlspecialchars( $codeblock, ENT_NOQUOTES );
     2592        $codeblock = preg_replace_callback( '/^\n+/',
     2593            array( &$this, '_doFencedCodeBlocks_newlines' ), $codeblock );
    25772594        $codeblock = "<pre><code>$codeblock</code></pre>";
    2578         return "\n\n".$this->hashBlock($codeblock)."\n\n";
    2579     }
    2580     function _doFencedCodeBlocks_newlines($matches) {
    2581         return str_repeat("<br$this->empty_element_suffix",
    2582             strlen($matches[0]));
     2595
     2596        return "\n\n" . $this->hashBlock( $codeblock ) . "\n\n";
     2597    }
     2598
     2599    function _doFencedCodeBlocks_newlines( $matches ) {
     2600        return str_repeat( "<br$this->empty_element_suffix",
     2601            strlen( $matches[0] ) );
    25832602    }
    25842603
     
    25922611        '*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
    25932612        '_' => '(?<=\S|^)(?<!_)_(?![a-zA-Z0-9_])',
    2594         );
     2613    );
    25952614    var $strong_relist = array(
    25962615        ''   => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S|$)(?![.,:;]\s)',
    25972616        '**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
    25982617        '__' => '(?<=\S|^)(?<!_)__(?![a-zA-Z0-9_])',
    2599         );
     2618    );
    26002619    var $em_strong_relist = array(
    26012620        ''    => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S|$)(?![.,:;]\s)',
    26022621        '***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
    26032622        '___' => '(?<=\S|^)(?<!_)___(?![a-zA-Z0-9_])',
    2604         );
    2605 
    2606 
    2607     function formParagraphs($text) {
    2608     #
    2609     #   Params:
    2610     #       $text - string to process with html <p> tags
    2611     #
     2623    );
     2624
     2625    function formParagraphs( $text ) {
     2626        #
     2627        #   Params:
     2628        #       $text - string to process with html <p> tags
     2629        #
    26122630        # Strip leading and trailing lines:
    2613         $text = preg_replace('/\A\n+|\n+\z/', '', $text);
    2614        
    2615         $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
     2631        $text = preg_replace( '/\A\n+|\n+\z/', '', $text );
     2632
     2633        $grafs = preg_split( '/\n{2,}/', $text, - 1, PREG_SPLIT_NO_EMPTY );
    26162634
    26172635        #
    26182636        # Wrap <p> tags and unhashify HTML blocks
    26192637        #
    2620         foreach ($grafs as $key => $value) {
    2621             $value = trim($this->runSpanGamut($value));
    2622            
     2638        foreach ( $grafs as $key => $value ) {
     2639            $value = trim( $this->runSpanGamut( $value ) );
     2640
    26232641            # Check if this should be enclosed in a paragraph.
    26242642            # Clean tag hashes & block tag hashes are left alone.
    2625             $is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value);
    2626            
    2627             if ($is_p) {
     2643            $is_p = ! preg_match( '/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value );
     2644
     2645            if ( $is_p ) {
    26282646                $value = "<p>$value</p>";
    26292647            }
    2630             $grafs[$key] = $value;
    2631         }
    2632        
    2633         # Join grafs in one text, then unhash HTML tags. 
    2634         $text = implode("\n\n", $grafs);
    2635        
     2648            $grafs[ $key ] = $value;
     2649        }
     2650
     2651        # Join grafs in one text, then unhash HTML tags.
     2652        $text = implode( "\n\n", $grafs );
     2653
    26362654        # Finish by removing any tag hashes still present in $text.
    2637         $text = $this->unhash($text);
    2638        
     2655        $text = $this->unhash( $text );
     2656
    26392657        return $text;
    26402658    }
    2641    
    2642    
     2659
    26432660    ### Footnotes
    2644    
    2645     function stripFootnotes($text) {
    2646     #
    2647     # Strips link definitions from text, stores the URLs and titles in
    2648     # hash references.
    2649     #
     2661
     2662    function stripFootnotes( $text ) {
     2663        #
     2664        # Strips link definitions from text, stores the URLs and titles in
     2665        # hash references.
     2666        #
    26502667        $less_than_tab = $this->tab_width - 1;
    26512668
    26522669        # Link defs are in the form: [^id]: url "optional title"
    2653         $text = preg_replace_callback('{
    2654             ^[ ]{0,'.$less_than_tab.'}\[\^(.+?)\][ ]?:  # note_id = $1
     2670        $text = preg_replace_callback( '{
     2671            ^[ ]{0,' . $less_than_tab . '}\[\^(.+?)\][ ]?:  # note_id = $1
    26552672              [ ]*
    26562673              \n?                   # maybe *one* newline
    26572674            (                       # text = $2 (no blank lines allowed)
    2658                 (?:                 
     2675                (?:
    26592676                    .+              # actual text
    26602677                |
    2661                     \n              # newlines but 
     2678                    \n              # newlines but
    26622679                    (?!\[\^.+?\]:\s)# negative lookahead for footnote marker.
    2663                     (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed 
     2680                    (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed
    26642681                                    # by non-indented content
    26652682                )*
    2666             )       
     2683            )
    26672684            }xm',
    2668             array(&$this, '_stripFootnotes_callback'),
    2669             $text);
     2685            array( &$this, '_stripFootnotes_callback' ),
     2686            $text );
     2687
    26702688        return $text;
    26712689    }
    2672     function _stripFootnotes_callback($matches) {
    2673         $note_id = $this->fn_id_prefix . $matches[1];
    2674         $this->footnotes[$note_id] = $this->outdent($matches[2]);
     2690
     2691    function _stripFootnotes_callback( $matches ) {
     2692        $note_id                     = $this->fn_id_prefix . $matches[1];
     2693        $this->footnotes[ $note_id ] = $this->outdent( $matches[2] );
     2694
    26752695        return ''; # String that will replace the block
    26762696    }
    26772697
    2678 
    2679     function doFootnotes($text) {
    2680     #
    2681     # Replace footnote references in $text [^id] with a special text-token
    2682     # which will be replaced by the actual footnote marker in appendFootnotes.
    2683     #
    2684         if (!$this->in_anchor) {
    2685             $text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text);
    2686         }
     2698    function doFootnotes( $text ) {
     2699        #
     2700        # Replace footnote references in $text [^id] with a special text-token
     2701        # which will be replaced by the actual footnote marker in appendFootnotes.
     2702        #
     2703        if ( ! $this->in_anchor ) {
     2704            $text = preg_replace( '{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text );
     2705        }
     2706
    26872707        return $text;
    26882708    }
    26892709
    2690    
    2691     function appendFootnotes($text) {
    2692     #
    2693     # Append footnote list to text.
    2694     #
    2695         $text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
    2696             array(&$this, '_appendFootnotes_callback'), $text);
    2697    
    2698         if (!empty($this->footnotes_ordered)) {
     2710    function appendFootnotes( $text ) {
     2711        #
     2712        # Append footnote list to text.
     2713        #
     2714        $text = preg_replace_callback( '{F\x1Afn:(.*?)\x1A:}',
     2715            array( &$this, '_appendFootnotes_callback' ), $text );
     2716
     2717        if ( ! empty( $this->footnotes_ordered ) ) {
    26992718            $text .= "\n\n";
    27002719            $text .= "<div class=\"footnotes\">\n";
    2701             $text .= "<hr". $this->empty_element_suffix ."\n";
     2720            $text .= "<hr" . $this->empty_element_suffix . "\n";
    27022721            $text .= "<ol>\n\n";
    2703            
     2722
    27042723            $attr = " rev=\"footnote\"";
    2705             if ($this->fn_backlink_class != "") {
     2724            if ( $this->fn_backlink_class != "" ) {
    27062725                $class = $this->fn_backlink_class;
    2707                 $class = $this->encodeAttribute($class);
     2726                $class = $this->encodeAttribute( $class );
    27082727                $attr .= " class=\"$class\"";
    27092728            }
    2710             if ($this->fn_backlink_title != "") {
     2729            if ( $this->fn_backlink_title != "" ) {
    27112730                $title = $this->fn_backlink_title;
    2712                 $title = $this->encodeAttribute($title);
     2731                $title = $this->encodeAttribute( $title );
    27132732                $attr .= " title=\"$title\"";
    27142733            }
    27152734            $num = 0;
    2716            
    2717             while (!empty($this->footnotes_ordered)) {
    2718                 $footnote = reset($this->footnotes_ordered);
    2719                 $note_id = key($this->footnotes_ordered);
    2720                 unset($this->footnotes_ordered[$note_id]);
    2721                
     2735
     2736            while ( ! empty( $this->footnotes_ordered ) ) {
     2737                $footnote = reset( $this->footnotes_ordered );
     2738                $note_id  = key( $this->footnotes_ordered );
     2739                unset( $this->footnotes_ordered[ $note_id ] );
     2740
    27222741                $footnote .= "\n"; # Need to append newline before parsing.
    2723                 $footnote = $this->runBlockGamut("$footnote\n");               
    2724                 $footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
    2725                     array(&$this, '_appendFootnotes_callback'), $footnote);
    2726                
    2727                 $attr = str_replace("%%", ++$num, $attr);
    2728                 $note_id = $this->encodeAttribute($note_id);
    2729                
     2742                $footnote = $this->runBlockGamut( "$footnote\n" );
     2743                $footnote = preg_replace_callback( '{F\x1Afn:(.*?)\x1A:}',
     2744                    array( &$this, '_appendFootnotes_callback' ), $footnote );
     2745
     2746                $attr    = str_replace( "%%", ++ $num, $attr );
     2747                $note_id = $this->encodeAttribute( $note_id );
     2748
    27302749                # Add backlink to last paragraph; create new paragraph if needed.
    27312750                $backlink = "<a href=\"#fnref:$note_id\"$attr>&#8617;</a>";
    2732                 if (preg_match('{</p>$}', $footnote)) {
    2733                     $footnote = substr($footnote, 0, -4) . "&#160;$backlink</p>";
     2751                if ( preg_match( '{</p>$}', $footnote ) ) {
     2752                    $footnote = substr( $footnote, 0, - 4 ) . "&#160;$backlink</p>";
    27342753                } else {
    27352754                    $footnote .= "\n\n<p>$backlink</p>";
    27362755                }
    2737                
     2756
    27382757                $text .= "<li id=\"fn:$note_id\">\n";
    27392758                $text .= $footnote . "\n";
    27402759                $text .= "</li>\n\n";
    27412760            }
    2742            
     2761
    27432762            $text .= "</ol>\n";
    27442763            $text .= "</div>";
    27452764        }
     2765
    27462766        return $text;
    27472767    }
    2748     function _appendFootnotes_callback($matches) {
     2768
     2769    function _appendFootnotes_callback( $matches ) {
    27492770        $node_id = $this->fn_id_prefix . $matches[1];
    2750        
     2771
    27512772        # Create footnote marker only if it has a corresponding footnote *and*
    27522773        # the footnote hasn't been used by another marker.
    2753         if (isset($this->footnotes[$node_id])) {
     2774        if ( isset( $this->footnotes[ $node_id ] ) ) {
    27542775            # Transfert footnote content to the ordered list.
    2755             $this->footnotes_ordered[$node_id] = $this->footnotes[$node_id];
    2756             unset($this->footnotes[$node_id]);
    2757            
    2758             $num = $this->footnote_counter++;
     2776            $this->footnotes_ordered[ $node_id ] = $this->footnotes[ $node_id ];
     2777            unset( $this->footnotes[ $node_id ] );
     2778
     2779            $num  = $this->footnote_counter ++;
    27592780            $attr = " rel=\"footnote\"";
    2760             if ($this->fn_link_class != "") {
     2781            if ( $this->fn_link_class != "" ) {
    27612782                $class = $this->fn_link_class;
    2762                 $class = $this->encodeAttribute($class);
     2783                $class = $this->encodeAttribute( $class );
    27632784                $attr .= " class=\"$class\"";
    27642785            }
    2765             if ($this->fn_link_title != "") {
     2786            if ( $this->fn_link_title != "" ) {
    27662787                $title = $this->fn_link_title;
    2767                 $title = $this->encodeAttribute($title);
     2788                $title = $this->encodeAttribute( $title );
    27682789                $attr .= " title=\"$title\"";
    27692790            }
    2770            
    2771             $attr = str_replace("%%", $num, $attr);
    2772             $node_id = $this->encodeAttribute($node_id);
    2773            
     2791
     2792            $attr    = str_replace( "%%", $num, $attr );
     2793            $node_id = $this->encodeAttribute( $node_id );
     2794
    27742795            return
    2775                 "<sup id=\"fnref:$node_id\">".
    2776                 "<a href=\"#fn:$node_id\"$attr>$num</a>".
     2796                "<sup id=\"fnref:$node_id\">" .
     2797                "<a href=\"#fn:$node_id\"$attr>$num</a>" .
    27772798                "</sup>";
    27782799        }
    2779        
    2780         return "[^".$matches[1]."]";
    2781     }
    2782        
    2783    
     2800
     2801        return "[^" . $matches[1] . "]";
     2802    }
     2803
    27842804    ### Abbreviations ###
    2785    
    2786     function stripAbbreviations($text) {
    2787     #
    2788     # Strips abbreviations from text, stores titles in hash references.
    2789     #
     2805
     2806    function stripAbbreviations( $text ) {
     2807        #
     2808        # Strips abbreviations from text, stores titles in hash references.
     2809        #
    27902810        $less_than_tab = $this->tab_width - 1;
    27912811
    27922812        # Link defs are in the form: [id]*: url "optional title"
    2793         $text = preg_replace_callback('{
    2794             ^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?:  # abbr_id = $1
    2795             (.*)                    # text = $2 (no blank lines allowed)   
     2813        $text = preg_replace_callback( '{
     2814            ^[ ]{0,' . $less_than_tab . '}\*\[(.+?)\][ ]?:  # abbr_id = $1
     2815            (.*)                    # text = $2 (no blank lines allowed)
    27962816            }xm',
    2797             array(&$this, '_stripAbbreviations_callback'),
    2798             $text);
     2817            array( &$this, '_stripAbbreviations_callback' ),
     2818            $text );
     2819
    27992820        return $text;
    28002821    }
    2801     function _stripAbbreviations_callback($matches) {
     2822
     2823    function _stripAbbreviations_callback( $matches ) {
    28022824        $abbr_word = $matches[1];
    28032825        $abbr_desc = $matches[2];
    2804         if ($this->abbr_word_re)
     2826        if ( $this->abbr_word_re ) {
    28052827            $this->abbr_word_re .= '|';
    2806         $this->abbr_word_re .= preg_quote($abbr_word);
    2807         $this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
     2828        }
     2829        $this->abbr_word_re .= preg_quote( $abbr_word );
     2830        $this->abbr_desciptions[ $abbr_word ] = trim( $abbr_desc );
     2831
    28082832        return ''; # String that will replace the block
    28092833    }
    2810    
    2811    
    2812     function doAbbreviations($text) {
    2813     #
    2814     # Find defined abbreviations in text and wrap them in <abbr> elements.
    2815     #
    2816         if ($this->abbr_word_re) {
    2817             // cannot use the /x modifier because abbr_word_re may
     2834
     2835    function doAbbreviations( $text ) {
     2836        #
     2837        # Find defined abbreviations in text and wrap them in <abbr> elements.
     2838        #