[DRE-commits] [SCM] ruby-redcarpet.git branch, master, updated. debian/2.1.1-3-2-gaa2cd63

Youhei SASAKI uwabami at gfd-dennou.org
Thu Jan 17 12:55:05 UTC 2013


The following commit has been merged in the master branch:
commit 3fea53c6d94bdc6607bf2616fae9c7a17e9e7138
Author: Youhei SASAKI <uwabami at gfd-dennou.org>
Date:   Thu Jan 17 21:45:01 2013 +0900

    Imported Upstream version 2.2.2

diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..e45e65f
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,2 @@
+source :rubygems
+gemspec
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..3605ca0
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,20 @@
+PATH
+  remote: .
+  specs:
+    redcarpet (2.1.1)
+
+GEM
+  remote: http://rubygems.org/
+  specs:
+    nokogiri (1.5.5)
+    rake (0.9.2.2)
+    rake-compiler (0.8.1)
+      rake
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  nokogiri
+  rake-compiler
+  redcarpet!
diff --git a/README.markdown b/README.markdown
index 5bca6a9..0b68c9f 100644
--- a/README.markdown
+++ b/README.markdown
@@ -9,14 +9,14 @@ case since version 2 -- it now has its own API, but retains the old name. Yes,
 that does mean that Redcarpet 2 is not backwards-compatible with the 1.X
 versions.
 
-Redcarpet is powered by the [Sundown](https://www.github.com/tanoku/sundown)
+Redcarpet is powered by the [Sundown](https://www.github.com/vmg/sundown)
 library. You might want to find out more about Sundown to see what makes this
 Ruby library so awesome.
 
 This library is written by people
 -------------------------------------------------------
 
-Redcarpet 2 has been rewritten from scratch by Vicent Martí (@tanoku). Why
+Redcarpet 2 has been rewritten from scratch by Vicent Martí (@vmg). Why
 are you not following me on Twitter?
 
 Redcarpet would not be possible without the Sundown library and its authors
@@ -32,7 +32,7 @@ extensions, but the parser is standalone and requires no installed libraries.
 
 The Redcarpet source (including Sundown as a submodule) is available at GitHub:
 
-    $ git clone git://github.com/tanoku/redcarpet.git
+    $ git clone git://github.com/vmg/redcarpet.git
 
 And it's like *really* simple to use
 ------------------------------------
@@ -78,7 +78,7 @@ settings, and reused between parses.
                     Two `~` characters mark the start of a strikethrough,
                     e.g. `this is ~~good~~ bad`
 
-                :lax_html_blocks - HTML blocks do not require to be surrounded
+                :lax_spacing - HTML blocks do not require to be surrounded
                     by an empty line as in the Markdown standard.
 
                 :space_after_headers - A space is always required between the
@@ -126,32 +126,33 @@ instantiating the renderer:
 
     Render::HTML.new(render_options={})
 
-    Initializes an HTML renderer. The following flags are available:
+Initializes an HTML renderer. The following flags are available:
 
-        :filter_html - do not allow any user-inputted HTML in the output
+    :filter_html - do not allow any user-inputted HTML in the output
 
-        :no_images - do not generate any `<img>` tags
+    :no_images - do not generate any `<img>` tags
 
-        :no_links - do not generate any `<a>` tags
+    :no_links - do not generate any `<a>` tags
 
-        :no_styles - do not generate any `<style>` tags
+    :no_styles - do not generate any `<style>` tags
 
-        :safe_links_only - only generate links for protocols which are considered safe
+    :safe_links_only - only generate links for protocols which are considered safe
 
-        :with_toc_data - add HTML anchors to each header in the output HTML,
-            to allow linking to each section.
+    :with_toc_data - add HTML anchors to each header in the output HTML,
+        to allow linking to each section.
 
-        :hard_wrap - insert HTML `<br>` tags inside on paragraphs where the origin
-            Markdown document had newlines (by default, Markdown ignores these
-            newlines).
+    :hard_wrap - insert HTML `<br>` tags inside on paragraphs where the origin
+        Markdown document had newlines (by default, Markdown ignores these
+        newlines).
 
-        :xhtml - output XHTML-conformant tags. This option is always enabled in the
-            `Render::XHTML` renderer.
+    :xhtml - output XHTML-conformant tags. This option is always enabled in the
+        `Render::XHTML` renderer.
 
+        :link_attributes - hash of extra attributes to add to links
 
-    Example:
+Example:
 
-        rndr = Redcarpet::Render::HTML.new(:no_links => true, :hard_wrap => true)
+    rndr = Redcarpet::Render::HTML.new(:no_links => true, :hard_wrap => true)
 
 
 The `HTML` renderer has an alternate version, `Redcarpet::Render::HTML_TOC`,
@@ -295,7 +296,7 @@ software accordingly, and force your users to install it. That's the
 only way to have reliable and predictable Markdown output on your program.
 
 Still, if major forces (let's say, tornadoes or other natural disasters) force you
-to keep a Markdown-compatibility later, Redcarpet also supports this:
+to keep a Markdown-compatibility layer, Redcarpet also supports this:
 
     require 'redcarpet/compat'
 
@@ -311,6 +312,10 @@ that's a maintance nightmare and won't work.
 On a related topic: if your Markdown gem has a `lib/markdown.rb` file that
 monkeypatches the Markdown class, you're a terrible human being. Just saying.
 
+Testing
+-------
+Tests run a lot faster without `bundle exec` :)
+
 Boring legal stuff
 ------------------
 
diff --git a/Rakefile b/Rakefile
index 3936a10..7c63124 100644
--- a/Rakefile
+++ b/Rakefile
@@ -3,7 +3,7 @@ require 'rake/clean'
 require 'rake/extensiontask'
 require 'digest/md5'
 
-task :default => :test
+task :default => [:test]
 
 # ==========================================================
 # Ruby Extension
@@ -110,7 +110,7 @@ task :update_gem do
 end
 
 desc 'Gather required Sundown sources into extension directory'
-task :gather => 'sundown/src/markdown.h' do |t|
+task :gather => 'sundown:checkout' do |t|
   files =
     FileList[
       'sundown/src/{markdown,buffer,stack,autolink,html_blocks}.h',
@@ -123,8 +123,9 @@ task :gather => 'sundown/src/markdown.h' do |t|
     :verbose => true
 end
 
-file 'sundown/src/markdown.h' do |t|
-  abort "The Sundown submodule is required."
+task 'sundown:checkout' do |t|
+  unless File.exists?('sundown/src/markdown.h')
+    sh 'git submodule init'
+    sh 'git submodule update'
+  end
 end
-
-
diff --git a/ext/redcarpet/autolink.c b/ext/redcarpet/autolink.c
index 1c3a070..b0d2616 100644
--- a/ext/redcarpet/autolink.c
+++ b/ext/redcarpet/autolink.c
@@ -15,12 +15,17 @@
  */
 
 #include "buffer.h"
+#include "autolink.h"
 
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
 
+#if defined(_WIN32)
+#define strncasecmp	_strnicmp
+#endif
+
 int
 sd_autolink_issafe(const uint8_t *link, size_t link_len)
 {
@@ -44,7 +49,7 @@ sd_autolink_issafe(const uint8_t *link, size_t link_len)
 }
 
 static size_t
-autolink_delim(uint8_t *data, size_t link_end, size_t offset, size_t size)
+autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size)
 {
 	uint8_t cclose, copen = 0;
 	size_t i;
@@ -128,7 +133,7 @@ autolink_delim(uint8_t *data, size_t link_end, size_t offset, size_t size)
 }
 
 static size_t
-check_domain(uint8_t *data, size_t size)
+check_domain(uint8_t *data, size_t size, int allow_short)
 {
 	size_t i, np = 0;
 
@@ -140,23 +145,37 @@ check_domain(uint8_t *data, size_t size)
 		else if (!isalnum(data[i]) && data[i] != '-') break;
 	}
 
-	/* a valid domain needs to have at least a dot.
-	 * that's as far as we get */
-	return np ? i : 0;
+	if (allow_short) {
+		/* We don't need a valid domain in the strict sense (with
+		 * least one dot; so just make sure it's composed of valid
+		 * domain characters and return the length of the the valid
+		 * sequence. */
+		return i;
+	} else {
+		/* a valid domain needs to have at least a dot.
+		 * that's as far as we get */
+		return np ? i : 0;
+	}
 }
 
 size_t
-sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
+sd_autolink__www(
+	size_t *rewind_p,
+	struct buf *link,
+	uint8_t *data,
+	size_t max_rewind,
+	size_t size,
+	unsigned int flags)
 {
 	size_t link_end;
 
-	if (offset > 0 && !ispunct(data[-1]) && !isspace(data[-1]))
+	if (max_rewind > 0 && !ispunct(data[-1]) && !isspace(data[-1]))
 		return 0;
 
 	if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0)
 		return 0;
 
-	link_end = check_domain(data, size);
+	link_end = check_domain(data, size, 0);
 
 	if (link_end == 0)
 		return 0;
@@ -164,7 +183,7 @@ sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offse
 	while (link_end < size && !isspace(data[link_end]))
 		link_end++;
 
-	link_end = autolink_delim(data, link_end, offset, size);
+	link_end = autolink_delim(data, link_end, max_rewind, size);
 
 	if (link_end == 0)
 		return 0;
@@ -176,12 +195,18 @@ sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offse
 }
 
 size_t
-sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
+sd_autolink__email(
+	size_t *rewind_p,
+	struct buf *link,
+	uint8_t *data,
+	size_t max_rewind,
+	size_t size,
+	unsigned int flags)
 {
 	size_t link_end, rewind;
 	int nb = 0, np = 0;
 
-	for (rewind = 0; rewind < offset; ++rewind) {
+	for (rewind = 0; rewind < max_rewind; ++rewind) {
 		uint8_t c = data[-rewind - 1];
 
 		if (isalnum(c))
@@ -213,7 +238,7 @@ sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t off
 	if (link_end < 2 || nb != 1 || np == 0)
 		return 0;
 
-	link_end = autolink_delim(data, link_end, offset, size);
+	link_end = autolink_delim(data, link_end, max_rewind, size);
 
 	if (link_end == 0)
 		return 0;
@@ -225,21 +250,32 @@ sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t off
 }
 
 size_t
-sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
+sd_autolink__url(
+	size_t *rewind_p,
+	struct buf *link,
+	uint8_t *data,
+	size_t max_rewind,
+	size_t size,
+	unsigned int flags)
 {
 	size_t link_end, rewind = 0, domain_len;
 
 	if (size < 4 || data[1] != '/' || data[2] != '/')
 		return 0;
 
-	while (rewind < offset && isalpha(data[-rewind - 1]))
+	while (rewind < max_rewind && isalpha(data[-rewind - 1]))
 		rewind++;
 
 	if (!sd_autolink_issafe(data - rewind, size + rewind))
 		return 0;
+
 	link_end = strlen("://");
 
-	domain_len = check_domain(data + link_end, size - link_end);
+	domain_len = check_domain(
+		data + link_end,
+		size - link_end,
+		flags & SD_AUTOLINK_SHORT_DOMAINS);
+
 	if (domain_len == 0)
 		return 0;
 
@@ -247,7 +283,7 @@ sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offse
 	while (link_end < size && !isspace(data[link_end]))
 		link_end++;
 
-	link_end = autolink_delim(data, link_end, offset, size);
+	link_end = autolink_delim(data, link_end, max_rewind, size);
 
 	if (link_end == 0)
 		return 0;
diff --git a/ext/redcarpet/autolink.h b/ext/redcarpet/autolink.h
index df9fd9c..65e0fe6 100644
--- a/ext/redcarpet/autolink.h
+++ b/ext/redcarpet/autolink.h
@@ -19,17 +19,32 @@
 
 #include "buffer.h"
 
-extern int
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+	SD_AUTOLINK_SHORT_DOMAINS = (1 << 0),
+};
+
+int
 sd_autolink_issafe(const uint8_t *link, size_t link_len);
 
-extern size_t
-sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);
+size_t
+sd_autolink__www(size_t *rewind_p, struct buf *link,
+	uint8_t *data, size_t offset, size_t size, unsigned int flags);
 
-extern size_t
-sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);
+size_t
+sd_autolink__email(size_t *rewind_p, struct buf *link,
+	uint8_t *data, size_t offset, size_t size, unsigned int flags);
 
-extern size_t
-sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);
+size_t
+sd_autolink__url(size_t *rewind_p, struct buf *link,
+	uint8_t *data, size_t offset, size_t size, unsigned int flags);
+
+#ifdef __cplusplus
+}
+#endif
 
 #endif
 
diff --git a/ext/redcarpet/buffer.c b/ext/redcarpet/buffer.c
index 3807fb9..47b40ce 100644
--- a/ext/redcarpet/buffer.c
+++ b/ext/redcarpet/buffer.c
@@ -127,7 +127,9 @@ bufprintf(struct buf *buf, const char *fmt, ...)
 
 	if (n < 0) {
 #ifdef _MSC_VER
+		va_start(ap, fmt);
 		n = _vscprintf(fmt, ap);
+		va_end(ap);
 #else
 		return;
 #endif
diff --git a/ext/redcarpet/buffer.h b/ext/redcarpet/buffer.h
index 8a1eb25..221d142 100644
--- a/ext/redcarpet/buffer.h
+++ b/ext/redcarpet/buffer.h
@@ -22,6 +22,10 @@
 #include <stdarg.h>
 #include <stdint.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #if defined(_MSC_VER)
 #define __attribute__(x)
 #define inline
@@ -85,4 +89,8 @@ void bufslurp(struct buf *, size_t);
 /* bufprintf: formatted printing to a buffer */
 void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3)));
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/ext/redcarpet/houdini.h b/ext/redcarpet/houdini.h
index d14147c..b4954c0 100644
--- a/ext/redcarpet/houdini.h
+++ b/ext/redcarpet/houdini.h
@@ -3,6 +3,10 @@
 
 #include "buffer.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifdef HOUDINI_USE_LOCALE
 #	define _isxdigit(c) isxdigit(c)
 #	define _isdigit(c) isdigit(c)
@@ -26,4 +30,8 @@ extern void houdini_unescape_url(struct buf *ob, const uint8_t *src, size_t size
 extern void houdini_escape_js(struct buf *ob, const uint8_t *src, size_t size);
 extern void houdini_unescape_js(struct buf *ob, const uint8_t *src, size_t size);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/ext/redcarpet/html.c b/ext/redcarpet/html.c
index 8c0d468..7f08ee8 100755
--- a/ext/redcarpet/html.c
+++ b/ext/redcarpet/html.c
@@ -491,6 +491,13 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
 {
 	struct html_renderopt *options = opaque;
 
+	/* set the level offset if this is the first header
+	 * we're parsing for the document */
+	if (options->toc_data.current_level == 0) {
+		options->toc_data.level_offset = level - 1;
+	}
+	level -= options->toc_data.level_offset;
+
 	if (level > options->toc_data.current_level) {
 		while (level > options->toc_data.current_level) {
 			BUFPUTSL(ob, "<ul>\n<li>\n");
@@ -516,7 +523,7 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
 static int
 toc_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque)
 {
-	if (content && content->size) 
+	if (content && content->size)
 		bufput(ob, content->data, content->size);
 	return 1;
 }
diff --git a/ext/redcarpet/html.h b/ext/redcarpet/html.h
index 4fbf3f4..4c8810d 100644
--- a/ext/redcarpet/html.h
+++ b/ext/redcarpet/html.h
@@ -21,10 +21,15 @@
 #include "buffer.h"
 #include <stdlib.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct html_renderopt {
 	struct {
 		int header_count;
 		int current_level;
+		int level_offset;
 	} toc_data;
 
 	unsigned int flags;
@@ -64,5 +69,9 @@ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *optio
 extern void
 sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
 
diff --git a/ext/redcarpet/html_smartypants.c b/ext/redcarpet/html_smartypants.c
index bb4089d..367c26a 100644
--- a/ext/redcarpet/html_smartypants.c
+++ b/ext/redcarpet/html_smartypants.c
@@ -22,6 +22,10 @@
 #include <stdio.h>
 #include <ctype.h>
 
+#if defined(_WIN32)
+#define snprintf	_snprintf		
+#endif
+
 struct smartypants_data {
 	int in_squote;
 	int in_dquote;
diff --git a/ext/redcarpet/markdown.c b/ext/redcarpet/markdown.c
index 18b1cfb..3253b0f 100644
--- a/ext/redcarpet/markdown.c
+++ b/ext/redcarpet/markdown.c
@@ -25,6 +25,10 @@
 #include <ctype.h>
 #include <stdio.h>
 
+#if defined(_WIN32)
+#define strncasecmp	_strnicmp
+#endif
+
 #define REF_TABLE_SIZE 8
 
 #define BUFFER_BLOCK 0
@@ -497,7 +501,7 @@ parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
 		if (data[i] == c && !_isspace(data[i - 1])) {
 
 			if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) {
-				if (!(i + 1 == size || _isspace(data[i + 1]) || ispunct(data[i + 1])))
+				if (i + i < size && isalnum(data[i + 1]))
 					continue;
 			}
 
@@ -592,6 +596,11 @@ char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t of
 	uint8_t c = data[0];
 	size_t ret;
 
+	if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) {
+		if (offset > 0 && !_isspace(data[-1]) && data[-1] != '>')
+			return 0;
+	}
+
 	if (size > 2 && data[1] != c) {
 		/* whitespace cannot follow an opening emphasis;
 		 * strikethrough only takes two characters '~~' */
@@ -767,7 +776,7 @@ char_autolink_www(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_
 
 	link = rndr_newbuf(rndr, BUFFER_SPAN);
 
-	if ((link_len = sd_autolink__www(&rewind, link, data, offset, size)) > 0) {
+	if ((link_len = sd_autolink__www(&rewind, link, data, offset, size, 0)) > 0) {
 		link_url = rndr_newbuf(rndr, BUFFER_SPAN);
 		BUFPUTSL(link_url, "http://");
 		bufput(link_url, link->data, link->size);
@@ -799,7 +808,7 @@ char_autolink_email(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, siz
 
 	link = rndr_newbuf(rndr, BUFFER_SPAN);
 
-	if ((link_len = sd_autolink__email(&rewind, link, data, offset, size)) > 0) {
+	if ((link_len = sd_autolink__email(&rewind, link, data, offset, size, 0)) > 0) {
 		ob->size -= rewind;
 		rndr->cb.autolink(ob, link, MKDA_EMAIL, rndr->opaque);
 	}
@@ -819,7 +828,7 @@ char_autolink_url(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_
 
 	link = rndr_newbuf(rndr, BUFFER_SPAN);
 
-	if ((link_len = sd_autolink__url(&rewind, link, data, offset, size)) > 0) {
+	if ((link_len = sd_autolink__url(&rewind, link, data, offset, size, 0)) > 0) {
 		ob->size -= rewind;
 		rndr->cb.autolink(ob, link, MKDA_NORMAL, rndr->opaque);
 	}
@@ -1150,9 +1159,10 @@ is_hrule(uint8_t *data, size_t size)
 	return n >= 3;
 }
 
-/* check if a line is a code fence; return its size if it is */
+/* check if a line begins with a code fence; return the
+ * width of the code fence */
 static size_t
-is_codefence(uint8_t *data, size_t size, struct buf *syntax)
+prefix_codefence(uint8_t *data, size_t size)
 {
 	size_t i = 0, n = 0;
 	uint8_t c;
@@ -1177,41 +1187,54 @@ is_codefence(uint8_t *data, size_t size, struct buf *syntax)
 	if (n < 3)
 		return 0;
 
-	if (syntax != NULL) {
-		size_t syn = 0;
+	return i;
+}
 
-		while (i < size && data[i] == ' ')
-			i++;
+/* check if a line is a code fence; return its size if it is */
+static size_t
+is_codefence(uint8_t *data, size_t size, struct buf *syntax)
+{
+	size_t i = 0, syn_len = 0;
+	uint8_t *syn_start;
 
-		syntax->data = data + i;
+	i = prefix_codefence(data, size);
+	if (i == 0)
+		return 0;
 
-		if (i < size && data[i] == '{') {
-			i++; syntax->data++;
+	while (i < size && data[i] == ' ')
+		i++;
 
-			while (i < size && data[i] != '}' && data[i] != '\n') {
-				syn++; i++;
-			}
+	syn_start = data + i;
 
-			if (i == size || data[i] != '}')
-				return 0;
+	if (i < size && data[i] == '{') {
+		i++; syn_start++;
 
-			/* strip all whitespace at the beginning and the end
-			 * of the {} block */
-			while (syn > 0 && _isspace(syntax->data[0])) {
-				syntax->data++; syn--;
-			}
+		while (i < size && data[i] != '}' && data[i] != '\n') {
+			syn_len++; i++;
+		}
 
-			while (syn > 0 && _isspace(syntax->data[syn - 1]))
-				syn--;
+		if (i == size || data[i] != '}')
+			return 0;
 
-			i++;
-		} else {
-			while (i < size && !_isspace(data[i])) {
-				syn++; i++;
-			}
+		/* strip all whitespace at the beginning and the end
+		 * of the {} block */
+		while (syn_len > 0 && _isspace(syn_start[0])) {
+			syn_start++; syn_len--;
 		}
 
-		syntax->size = syn;
+		while (syn_len > 0 && _isspace(syn_start[syn_len - 1]))
+			syn_len--;
+
+		i++;
+	} else {
+		while (i < size && !_isspace(data[i])) {
+			syn_len++; i++;
+		}
+	}
+
+	if (syntax) {
+		syntax->data = syn_start;
+		syntax->size = syn_len;
 	}
 
 	while (i < size && data[i] != '\n') {
@@ -1416,19 +1439,48 @@ parse_paragraph(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
 	while (i < size) {
 		for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */;
 
-		if (is_empty(data + i, size - i) || (level = is_headerline(data + i, size - i)) != 0)
+		if (is_empty(data + i, size - i))
+			break;
+
+		if ((level = is_headerline(data + i, size - i)) != 0)
+			break;
+
+		if (is_atxheader(rndr, data + i, size - i) ||
+			is_hrule(data + i, size - i) ||
+			prefix_quote(data + i, size - i)) {
+			end = i;
 			break;
+		}
 
-		if (rndr->ext_flags & MKDEXT_LAX_HTML_BLOCKS) {
-			if (data[i] == '<' && rndr->cb.blockhtml && parse_htmlblock(ob, rndr, data + i, size - i, 0)) {
+		/*
+		 * Early termination of a paragraph with the same logic
+		 * as Markdown 1.0.0. If this logic is applied, the
+		 * Markdown 1.0.3 test suite won't pass cleanly
+		 *
+		 * :: If the first character in a new line is not a letter,
+		 * let's check to see if there's some kind of block starting
+		 * here
+		 */
+		if ((rndr->ext_flags & MKDEXT_LAX_SPACING) && !isalnum(data[i])) {
+			if (prefix_oli(data + i, size - i) ||
+				prefix_uli(data + i, size - i)) {
 				end = i;
 				break;
 			}
-		}
 
-		if (is_atxheader(rndr, data + i, size - i) || is_hrule(data + i, size - i)) {
-			end = i;
-			break;
+			/* see if an html block starts here */
+			if (data[i] == '<' && rndr->cb.blockhtml &&
+				parse_htmlblock(ob, rndr, data + i, size - i, 0)) {
+				end = i;
+				break;
+			}
+
+			/* see if a code fence starts here */
+			if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 &&
+				is_codefence(data + i, size - i, NULL) != 0) {
+				end = i;
+				break;
+			}
 		}
 
 		i = end;
@@ -1500,9 +1552,10 @@ parse_fencedcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
 
 	while (beg < size) {
 		size_t fence_end;
+		struct buf fence_trail = { 0, 0, 0, 0 };
 
-		fence_end = is_codefence(data + beg, size - beg, NULL);
-		if (fence_end != 0) {
+		fence_end = is_codefence(data + beg, size - beg, &fence_trail);
+		if (fence_end != 0 && fence_trail.size == 0) {
 			beg += fence_end;
 			break;
 		}
@@ -1577,8 +1630,7 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
 {
 	struct buf *work = 0, *inter = 0;
 	size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
-	int in_empty = 0, has_inside_empty = 0;
-	size_t has_next_uli, has_next_oli;
+	int in_empty = 0, has_inside_empty = 0, in_fence = 0;
 
 	/* keeping track of the first indentation prefix */
 	while (orgpre < 3 && orgpre < size && data[orgpre] == ' ')
@@ -1606,6 +1658,8 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
 
 	/* process the following lines */
 	while (beg < size) {
+		size_t has_next_uli = 0, has_next_oli = 0;
+
 		end++;
 
 		while (end < size && data[end - 1] != '\n')
@@ -1625,8 +1679,17 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
 
 		pre = i;
 
-		has_next_uli = prefix_uli(data + beg + i, end - beg - i);
-		has_next_oli = prefix_oli(data + beg + i, end - beg - i);
+		if (rndr->ext_flags & MKDEXT_FENCED_CODE) {
+			if (is_codefence(data + beg + i, end - beg - i, NULL) != 0)
+				in_fence = !in_fence;
+		}
+
+		/* Only check for new list items if we are **not** inside
+		 * a fenced code block */
+		if (!in_fence) {
+			has_next_uli = prefix_uli(data + beg + i, end - beg - i);
+			has_next_oli = prefix_oli(data + beg + i, end - beg - i);
+		}
 
 		/* checking for ul/ol switch */
 		if (in_empty && (
@@ -1647,10 +1710,12 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
 			if (!sublist)
 				sublist = work->size;
 		}
-		/* joining only indented stuff after empty lines */
-		else if (in_empty && i < 4) {
-				*flags |= MKD_LI_END;
-				break;
+		/* joining only indented stuff after empty lines;
+		 * note that now we only require 1 space of indentation
+		 * to continue a list */
+		else if (in_empty && pre == 0) {
+			*flags |= MKD_LI_END;
+			break;
 		}
 		else if (in_empty) {
 			bufputc(work, '\n');
@@ -1758,7 +1823,12 @@ parse_atxheader(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
 /* htmlblock_end • checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */
 /*	returns the length on match, 0 otherwise */
 static size_t
-htmlblock_end(const char *tag, size_t tag_len, struct sd_markdown *rndr, uint8_t *data, size_t size)
+htmlblock_end_tag(
+	const char *tag,
+	size_t tag_len,
+	struct sd_markdown *rndr,
+	uint8_t *data,
+	size_t size)
 {
 	size_t i, w;
 
@@ -1776,25 +1846,60 @@ htmlblock_end(const char *tag, size_t tag_len, struct sd_markdown *rndr, uint8_t
 	i += w;
 	w = 0;
 
-	if (rndr->ext_flags & MKDEXT_LAX_HTML_BLOCKS) {
-		if (i < size)
-			w = is_empty(data + i, size - i);
-	} else  {
-		if (i < size && (w = is_empty(data + i, size - i)) == 0)
-			return 0; /* non-blank line after tag line */
-	}
+	if (i < size)
+		w = is_empty(data + i, size - i);
 
 	return i + w;
 }
 
+static size_t
+htmlblock_end(const char *curtag,
+	struct sd_markdown *rndr,
+	uint8_t *data,
+	size_t size,
+	int start_of_line)
+{
+	size_t tag_size = strlen(curtag);
+	size_t i = 1, end_tag;
+	int block_lines = 0;
+
+	while (i < size) {
+		i++;
+		while (i < size && !(data[i - 1] == '<' && data[i] == '/')) {
+			if (data[i] == '\n')
+				block_lines++;
+
+			i++;
+		}
+
+		/* If we are only looking for unindented tags, skip the tag
+		 * if it doesn't follow a newline.
+		 *
+		 * The only exception to this is if the tag is still on the
+		 * initial line; in that case it still counts as a closing
+		 * tag
+		 */
+		if (start_of_line && block_lines > 0 && data[i - 2] != '\n')
+			continue;
+
+		if (i + 2 + tag_size >= size)
+			break;
+
+		end_tag = htmlblock_end_tag(curtag, tag_size, rndr, data + i - 1, size - i + 1);
+		if (end_tag)
+			return i + end_tag - 1;
+	}
+
+	return 0;
+}
+
 
 /* parse_htmlblock • parsing of inline HTML block */
 static size_t
 parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render)
 {
-	size_t i, j = 0;
+	size_t i, j = 0, tag_end;
 	const char *curtag = NULL;
-	int found;
 	struct buf work = { data, 0, 0, 0 };
 
 	/* identification of the opening tag */
@@ -1855,40 +1960,23 @@ parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
 
 	/* looking for an unindented matching closing tag */
 	/*	followed by a blank line */
-	i = 1;
-	found = 0;
+	tag_end = htmlblock_end(curtag, rndr, data, size, 1);
 
 	/* if not found, trying a second pass looking for indented match */
 	/* but not if tag is "ins" or "del" (following original Markdown.pl) */
-	if (strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) {
-		size_t tag_size = strlen(curtag);
-		i = 1;
-		while (i < size) {
-			i++;
-			while (i < size && !(data[i - 1] == '<' && data[i] == '/'))
-				i++;
-
-			if (i + 2 + tag_size >= size)
-				break;
-
-			j = htmlblock_end(curtag, tag_size, rndr, data + i - 1, size - i + 1);
-
-			if (j) {
-				i += j - 1;
-				found = 1;
-				break;
-			}
-		}
+	if (!tag_end && strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) {
+		tag_end = htmlblock_end(curtag, rndr, data, size, 0);
 	}
 
-	if (!found) return 0;
+	if (!tag_end)
+		return 0;
 
 	/* the end of the block has been found */
-	work.size = i;
+	work.size = tag_end;
 	if (do_render && rndr->cb.blockhtml)
 		rndr->cb.blockhtml(ob, &work, rndr->opaque);
 
-	return i;
+	return tag_end;
 }
 
 static void
@@ -2460,9 +2548,9 @@ sd_markdown_free(struct sd_markdown *md)
 void
 sd_version(int *ver_major, int *ver_minor, int *ver_revision)
 {
-	*ver_major = UPSKIRT_VER_MAJOR;
-	*ver_minor = UPSKIRT_VER_MINOR;
-	*ver_revision = UPSKIRT_VER_REVISION;
+	*ver_major = SUNDOWN_VER_MAJOR;
+	*ver_minor = SUNDOWN_VER_MINOR;
+	*ver_revision = SUNDOWN_VER_REVISION;
 }
 
 /* vim: set filetype=c: */
diff --git a/ext/redcarpet/markdown.h b/ext/redcarpet/markdown.h
index f8a47c6..6f6553e 100644
--- a/ext/redcarpet/markdown.h
+++ b/ext/redcarpet/markdown.h
@@ -22,10 +22,14 @@
 #include "buffer.h"
 #include "autolink.h"
 
-#define UPSKIRT_VERSION "1.15.2"
-#define UPSKIRT_VER_MAJOR 1
-#define UPSKIRT_VER_MINOR 15
-#define UPSKIRT_VER_REVISION 2
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SUNDOWN_VERSION "1.16.0"
+#define SUNDOWN_VER_MAJOR 1
+#define SUNDOWN_VER_MINOR 16
+#define SUNDOWN_VER_REVISION 0
 
 /********************
  * TYPE DEFINITIONS *
@@ -52,9 +56,9 @@ enum mkd_extensions {
 	MKDEXT_FENCED_CODE = (1 << 2),
 	MKDEXT_AUTOLINK = (1 << 3),
 	MKDEXT_STRIKETHROUGH = (1 << 4),
-	MKDEXT_LAX_HTML_BLOCKS = (1 << 5),
 	MKDEXT_SPACE_HEADERS = (1 << 6),
 	MKDEXT_SUPERSCRIPT = (1 << 7),
+	MKDEXT_LAX_SPACING = (1 << 8),
 };
 
 /* sd_callbacks - functions for rendering parsed data */
@@ -125,6 +129,10 @@ sd_markdown_free(struct sd_markdown *md);
 extern void
 sd_version(int *major, int *minor, int *revision);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
 
 /* vim: set filetype=c: */
diff --git a/ext/redcarpet/rc_markdown.c b/ext/redcarpet/rc_markdown.c
index 4b42e5c..da1abcc 100644
--- a/ext/redcarpet/rc_markdown.c
+++ b/ext/redcarpet/rc_markdown.c
@@ -44,8 +44,8 @@ static void rb_redcarpet_md_flags(VALUE hash, unsigned int *enabled_extensions_p
 	if (rb_hash_lookup(hash, CSTR2SYM("strikethrough")) == Qtrue)
 		extensions |= MKDEXT_STRIKETHROUGH;
 
-	if (rb_hash_lookup(hash, CSTR2SYM("lax_html_blocks")) == Qtrue)
-		extensions |= MKDEXT_LAX_HTML_BLOCKS;
+	if (rb_hash_lookup(hash, CSTR2SYM("lax_spacing")) == Qtrue)
+		extensions |= MKDEXT_LAX_SPACING;
 
 	if (rb_hash_lookup(hash, CSTR2SYM("space_after_headers")) == Qtrue)
 		extensions |= MKDEXT_SPACE_HEADERS;
diff --git a/ext/redcarpet/rc_render.c b/ext/redcarpet/rc_render.c
index 8e1c564..63cc558 100644
--- a/ext/redcarpet/rc_render.c
+++ b/ext/redcarpet/rc_render.c
@@ -234,6 +234,27 @@ rndr_doc_footer(struct buf *ob, void *opaque)
 	BLOCK_CALLBACK("doc_footer", 0);
 }
 
+static int
+cb_link_attribute(VALUE key, VALUE val, VALUE payload)
+{
+	struct buf *ob = (struct buf *)payload;
+	key = rb_obj_as_string(key);
+	val = rb_obj_as_string(val);
+	bufprintf(ob, " %s=\"%s\"", StringValueCStr(key), StringValueCStr(val));
+	return 0;
+}
+
+static void
+rndr_link_attributes(struct buf *ob, const struct buf *url, void *opaque)
+{
+	struct redcarpet_renderopt *opt = opaque;
+	struct rb_redcarpet_rndr *rndr;
+
+	Data_Get_Struct(opt->self, struct rb_redcarpet_rndr, rndr);
+	Check_Type(opt->link_attributes, T_HASH);
+	rb_hash_foreach(opt->link_attributes, &cb_link_attribute, (VALUE)ob);
+}
+
 static struct sd_callbacks rb_redcarpet_callbacks = {
 	rndr_blockcode,
 	rndr_blockquote,
@@ -342,12 +363,11 @@ static VALUE rb_redcarpet_html_init(int argc, VALUE *argv, VALUE self)
 {
 	struct rb_redcarpet_rndr *rndr;
 	unsigned int render_flags = 0;
-	VALUE hash;
+	VALUE hash, link_attr = Qnil;
 
 	Data_Get_Struct(self, struct rb_redcarpet_rndr, rndr);
 
-	if (rb_scan_args(argc, argv, "01", &hash) == 1)
-	{
+	if (rb_scan_args(argc, argv, "01", &hash) == 1) {
 		Check_Type(hash, T_HASH);
 
 		/* escape_html */
@@ -382,11 +402,18 @@ static VALUE rb_redcarpet_html_init(int argc, VALUE *argv, VALUE self)
 
 		if (rb_hash_aref(hash, CSTR2SYM("xhtml")) == Qtrue)
 			render_flags |= HTML_USE_XHTML;
+
+		link_attr = rb_hash_aref(hash, CSTR2SYM("link_attributes"));
 	}
 
 	sdhtml_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, render_flags);
 	rb_redcarpet__overload(self, rb_cRenderHTML);
 
+	if (!NIL_P(link_attr)) {
+		rndr->options.link_attributes = link_attr;
+		rndr->options.html.link_attributes = &rndr_link_attributes;
+	}
+
 	return Qnil;
 }
 
diff --git a/ext/redcarpet/redcarpet.h b/ext/redcarpet/redcarpet.h
index 1c4133f..e2f6b97 100644
--- a/ext/redcarpet/redcarpet.h
+++ b/ext/redcarpet/redcarpet.h
@@ -21,6 +21,7 @@ extern void Init_redcarpet_rndr();
 
 struct redcarpet_renderopt {
 	struct html_renderopt html;
+	VALUE link_attributes;
 	VALUE self;
 	VALUE base_class;
 #ifdef HAVE_RUBY_ENCODING_H
diff --git a/ext/redcarpet/stack.h b/ext/redcarpet/stack.h
index e3b79d9..08ff030 100644
--- a/ext/redcarpet/stack.h
+++ b/ext/redcarpet/stack.h
@@ -3,6 +3,10 @@
 
 #include <stdlib.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct stack {
 	void **item;
 	size_t size;
@@ -18,4 +22,8 @@ int stack_push(struct stack *, void *);
 void *stack_pop(struct stack *);
 void *stack_top(struct stack *);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/lib/redcarpet.rb b/lib/redcarpet.rb
index edd6ad0..2dc4ba5 100644
--- a/lib/redcarpet.rb
+++ b/lib/redcarpet.rb
@@ -1,7 +1,7 @@
 require 'redcarpet.so'
 
 module Redcarpet
-  VERSION = '2.1.1'
+  VERSION = '2.2.2'
 
   class Markdown
     attr_reader :renderer
@@ -77,7 +77,7 @@ class RedcarpetCompat
     :fenced_code => :fenced_code_blocks,
     :filter_html => :filter_html,
     :hard_wrap => :hard_wrap,
-    :lax_htmlblock => :lax_html_blocks,
+    :lax_htmlblock => :lax_spacing,
     :no_image => :no_images,
     :no_intraemphasis => :no_intra_emphasis,
     :no_links => :no_links,
diff --git a/metadata.yml b/metadata.yml
index a64a872..4f687a7 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,13 +1,13 @@
 --- !ruby/object:Gem::Specification 
 name: redcarpet
 version: !ruby/object:Gem::Version 
-  hash: 9
+  hash: 3
   prerelease: 
   segments: 
   - 2
-  - 1
-  - 1
-  version: 2.1.1
+  - 2
+  - 2
+  version: 2.2.2
 platform: ruby
 authors: 
 - "Natacha Port\xC3\xA9"
@@ -16,10 +16,11 @@ autorequire:
 bindir: bin
 cert_chain: []
 
-date: 2011-09-14 00:00:00 Z
+date: 2012-10-19 00:00:00 +02:00
+default_executable: 
 dependencies: 
 - !ruby/object:Gem::Dependency 
-  name: rake-compiler
+  name: nokogiri
   prerelease: false
   requirement: &id001 !ruby/object:Gem::Requirement 
     none: false
@@ -32,6 +33,20 @@ dependencies:
         version: "0"
   type: :development
   version_requirements: *id001
+- !ruby/object:Gem::Dependency 
+  name: rake-compiler
+  prerelease: false
+  requirement: &id002 !ruby/object:Gem::Requirement 
+    none: false
+    requirements: 
+    - - ">="
+      - !ruby/object:Gem::Version 
+        hash: 3
+        segments: 
+        - 0
+        version: "0"
+  type: :development
+  version_requirements: *id002
 description: A fast, safe and extensible Markdown to (X)HTML parser
 email: vicent at github.com
 executables: 
@@ -42,6 +57,8 @@ extra_rdoc_files:
 - COPYING
 files: 
 - COPYING
+- Gemfile
+- Gemfile.lock
 - README.markdown
 - Rakefile
 - bin/redcarpet
@@ -70,7 +87,8 @@ files:
 - lib/redcarpet/render_strip.rb
 - redcarpet.gemspec
 - test/redcarpet_test.rb
-homepage: http://github.com/tanoku/redcarpet
+has_rdoc: true
+homepage: http://github.com/vmg/redcarpet
 licenses: []
 
 post_install_message: 
@@ -99,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
 requirements: []
 
 rubyforge_project: 
-rubygems_version: 1.8.15
+rubygems_version: 1.6.2
 signing_key: 
 specification_version: 3
 summary: Markdown that smells nice
diff --git a/redcarpet.gemspec b/redcarpet.gemspec
index ce9fc15..bf268e0 100644
--- a/redcarpet.gemspec
+++ b/redcarpet.gemspec
@@ -1,16 +1,18 @@
 # encoding: utf-8
 Gem::Specification.new do |s|
   s.name = 'redcarpet'
-  s.version = '2.1.1'
+  s.version = '2.2.2'
   s.summary = "Markdown that smells nice"
   s.description = 'A fast, safe and extensible Markdown to (X)HTML parser'
-  s.date = '2011-09-14'
+  s.date = '2012-10-19'
   s.email = 'vicent at github.com'
-  s.homepage = 'http://github.com/tanoku/redcarpet'
+  s.homepage = 'http://github.com/vmg/redcarpet'
   s.authors = ["Natacha Porté", "Vicent Martí"]
   # = MANIFEST =
   s.files = %w[
     COPYING
+    Gemfile
+    Gemfile.lock
     README.markdown
     Rakefile
     bin/redcarpet
@@ -47,5 +49,6 @@ Gem::Specification.new do |s|
   s.extensions = ["ext/redcarpet/extconf.rb"]
   s.executables = ["redcarpet"]
   s.require_paths = ["lib"]
+  s.add_development_dependency "nokogiri"
   s.add_development_dependency "rake-compiler"
 end
diff --git a/test/redcarpet_test.rb b/test/redcarpet_test.rb
index 70e40ea..00ff013 100644
--- a/test/redcarpet_test.rb
+++ b/test/redcarpet_test.rb
@@ -127,6 +127,12 @@ EOE
     
     assert rd =~ /<br>/
   end
+
+  def test_that_link_attributes_work
+    rndr = Redcarpet::Render::HTML.new(:link_attributes => {:rel => 'blank'})
+    md = Redcarpet::Markdown.new(rndr)
+    assert md.render('This is a [simple](http://test.com) test.').include?('rel="blank"')
+  end
 end
 
 class MarkdownTest < Test::Unit::TestCase
@@ -187,7 +193,7 @@ class MarkdownTest < Test::Unit::TestCase
   end
 
   def test_para_before_block_html_should_not_wrap_in_p_tag
-    markdown = render_with({:lax_html_blocks => true},
+    markdown = render_with({:lax_spacing => true},
       "Things to watch out for\n" +
       "<ul>\n<li>Blah</li>\n</ul>\n")
 
@@ -311,6 +317,15 @@ fenced
     assert render_with({:fenced_code_blocks => true}, text) =~ /<code/
   end
 
+  def test_that_fenced_flag_works_without_space
+    text = "foo\nbar\n```\nsome\ncode\n```\nbaz"
+    out = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :fenced_code_blocks => true, :lax_spacing => true).render(text)
+    assert out.include?("<pre><code>")
+
+    out = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :fenced_code_blocks => true).render(text)
+    assert !out.include?("<pre><code>")
+  end
+
   def test_that_headers_are_linkable
     markdown = @markdown.render('### Hello [GitHub](http://github.com)')
     html_equal "<h3>Hello <a href=\"http://github.com\">GitHub</a></h3>", markdown
@@ -327,6 +342,14 @@ text
     rd = render_with({:space_after_headers => true}, "#123 a header yes\n")
     assert rd !~ /<h1>/
   end
+
+  def test_proper_intra_emphasis
+    md = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :no_intra_emphasis => true)
+    assert render_with({:no_intra_emphasis => true}, "http://en.wikipedia.org/wiki/Dave_Allen_(comedian)") !~ /<em>/
+    assert render_with({:no_intra_emphasis => true}, "this fails: hello_world_") !~ /<em>/
+    assert render_with({:no_intra_emphasis => true}, "this also fails: hello_world_#bye") !~ /<em>/
+    assert render_with({:no_intra_emphasis => true}, "this works: hello_my_world") !~ /<em>/
+  end
 end
 
 class CustomRenderTest < Test::Unit::TestCase

-- 
ruby-redcarpet.git



More information about the Pkg-ruby-extras-commits mailing list