cmark

My personal build of CMark ✏️

Commit
0e4769d5c1e254fa1747701d2da708d0cb61d0c3
Parent
5ba5740f7e4404c0111a37f77db42c105740a6ff
Author
John MacFarlane <jgm@berkeley.edu>
Date

Merge pull request #38 from nwellnhof/chunks_for_links

Store link URL and title as cmark_chunk

Diffstat

9 files changed, 79 insertions, 72 deletions

Status File Name N° Changes Insertions Deletions
Modified src/chunk.h 17 13 4
Modified src/html.c 18 10 8
Modified src/inlines.c 67 38 29
Modified src/inlines.h 4 2 2
Modified src/node.c 27 6 21
Modified src/node.h 4 2 2
Modified src/references.c 4 2 2
Modified src/references.h 4 2 2
Modified src/xml.c 6 4 2
diff --git a/src/chunk.h b/src/chunk.h
@@ -7,6 +7,8 @@
 #include "cmark_ctype.h"
 #include "buffer.h"
 
+#define CMARK_CHUNK_EMPTY { NULL, 0, 0 }
+
 typedef struct {
 	unsigned char *data;
 	int len;
@@ -78,10 +80,17 @@ static inline void cmark_chunk_set_cstr(cmark_chunk *c, const char *str)
 	if (c->alloc) {
 		free(c->data);
 	}
-	c->len   = strlen(str);
-	c->data  = (unsigned char *)malloc(c->len + 1);
-	c->alloc = 1;
-	memcpy(c->data, str, c->len + 1);
+	if (str == NULL) {
+		c->len   = 0;
+		c->data  = NULL;
+		c->alloc = 0;
+	}
+	else {
+		c->len   = strlen(str);
+		c->data  = (unsigned char *)malloc(c->len + 1);
+		c->alloc = 1;
+		memcpy(c->data, str, c->len + 1);
+	}
 }
 
 static inline cmark_chunk cmark_chunk_literal(const char *data)
diff --git a/src/html.c b/src/html.c
@@ -261,12 +261,13 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
 	case CMARK_NODE_LINK:
 		if (entering) {
 			cmark_strbuf_puts(html, "<a href=\"");
-			if (node->as.link.url)
-				escape_href(html, node->as.link.url, -1);
+			escape_href(html, node->as.link.url.data,
+				    node->as.link.url.len);
 
-			if (node->as.link.title) {
+			if (node->as.link.title.len) {
 				cmark_strbuf_puts(html, "\" title=\"");
-				escape_html(html, node->as.link.title, -1);
+				escape_html(html, node->as.link.title.data,
+					    node->as.link.title.len);
 			}
 
 			cmark_strbuf_puts(html, "\">");
@@ -278,15 +279,16 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
 	case CMARK_NODE_IMAGE:
 		if (entering) {
 			cmark_strbuf_puts(html, "<img src=\"");
-			if (node->as.link.url)
-				escape_href(html, node->as.link.url, -1);
+			escape_href(html, node->as.link.url.data,
+				    node->as.link.url.len);
 
 			cmark_strbuf_puts(html, "\" alt=\"");
 			state->plain = node;
 		} else {
-			if (node->as.link.title) {
+			if (node->as.link.title.len) {
 				cmark_strbuf_puts(html, "\" title=\"");
-				escape_html(html, node->as.link.title, -1);
+				escape_html(html, node->as.link.title.data,
+					    node->as.link.title.len);
 			}
 
 			cmark_strbuf_puts(html, "\" />");
diff --git a/src/inlines.c b/src/inlines.c
@@ -59,31 +59,33 @@ static void subject_from_buf(subject *e, cmark_strbuf *buffer,
                              cmark_reference_map *refmap);
 static int subject_find_special_char(subject *subj, int options);
 
-static unsigned char *cmark_clean_autolink(cmark_chunk *url, int is_email)
+static cmark_chunk cmark_clean_autolink(cmark_chunk *url, int is_email)
 {
 	cmark_strbuf buf = GH_BUF_INIT;
 
 	cmark_chunk_trim(url);
 
-	if (url->len == 0)
-		return NULL;
+	if (url->len == 0) {
+		cmark_chunk result = CMARK_CHUNK_EMPTY;
+		return result;
+	}
 
 	if (is_email)
 		cmark_strbuf_puts(&buf, "mailto:");
 
 	houdini_unescape_html_f(&buf, url->data, url->len);
-	return cmark_strbuf_detach(&buf);
+	return cmark_chunk_buf_detach(&buf);
 }
 
-static inline cmark_node *make_link(cmark_node *label, unsigned char *url, unsigned char *title)
+static inline cmark_node *make_link(cmark_node *label, cmark_chunk *url, cmark_chunk *title)
 {
 	cmark_node* e = (cmark_node *)calloc(1, sizeof(*e));
 	if(e != NULL) {
 		e->type = CMARK_NODE_LINK;
 		e->first_child   = label;
 		e->last_child    = label;
-		e->as.link.url   = url;
-		e->as.link.title = title;
+		e->as.link.url   = *url;
+		e->as.link.title = *title;
 		e->next = NULL;
 		label->parent = e;
 	}
@@ -92,7 +94,9 @@ static inline cmark_node *make_link(cmark_node *label, unsigned char *url, unsig
 
 static inline cmark_node* make_autolink(cmark_node* label, cmark_chunk url, int is_email)
 {
-	return make_link(label, cmark_clean_autolink(&url, is_email), NULL);
+	cmark_chunk clean_url = cmark_clean_autolink(&url, is_email);
+	cmark_chunk title = CMARK_CHUNK_EMPTY;
+	return make_link(label, &clean_url, &title);
 }
 
 // Create an inline with a literal string value.
@@ -134,19 +138,20 @@ static inline cmark_node* make_simple(cmark_node_type t)
 	return e;
 }
 
-static unsigned char *bufdup(const unsigned char *buf)
+// Duplicate a chunk by creating a copy of the buffer not by reusing the
+// buffer like cmark_chunk_dup does.
+static cmark_chunk chunk_clone(cmark_chunk *src)
 {
-	unsigned char *new_buf = NULL;
+	cmark_chunk c;
+	int len = src->len;
 
-	if (buf) {
-		int len = strlen((char *)buf);
-		new_buf = (unsigned char *)calloc(len + 1, sizeof(*new_buf));
-		if(new_buf != NULL) {
-			memcpy(new_buf, buf, len + 1);
-		}
-	}
+	c.len   = len;
+	c.data  = (unsigned char *)malloc(len + 1);
+	c.alloc = 1;
+	memcpy(c.data, src->data, len);
+	c.data[len] = '\0';
 
-	return new_buf;
+       return c;
 }
 
 static void subject_from_buf(subject *e, cmark_strbuf *buffer,
@@ -622,14 +627,16 @@ static cmark_node *make_str_with_entities(cmark_chunk *content)
 
 // Clean a URL: remove surrounding whitespace and surrounding <>,
 // and remove \ that escape punctuation.
-unsigned char *cmark_clean_url(cmark_chunk *url)
+cmark_chunk cmark_clean_url(cmark_chunk *url)
 {
 	cmark_strbuf buf = GH_BUF_INIT;
 
 	cmark_chunk_trim(url);
 
-	if (url->len == 0)
-		return NULL;
+	if (url->len == 0) {
+		cmark_chunk result = CMARK_CHUNK_EMPTY;
+		return result;
+	}
 
 	if (url->data[0] == '<' && url->data[url->len - 1] == '>') {
 		houdini_unescape_html_f(&buf, url->data + 1, url->len - 2);
@@ -638,16 +645,18 @@ unsigned char *cmark_clean_url(cmark_chunk *url)
 	}
 
 	cmark_strbuf_unescape(&buf);
-	return buf.size == 0 ? NULL : cmark_strbuf_detach(&buf);
+	return cmark_chunk_buf_detach(&buf);
 }
 
-unsigned char *cmark_clean_title(cmark_chunk *title)
+cmark_chunk cmark_clean_title(cmark_chunk *title)
 {
 	cmark_strbuf buf = GH_BUF_INIT;
 	unsigned char first, last;
 
-	if (title->len == 0)
-		return NULL;
+	if (title->len == 0) {
+		cmark_chunk result = CMARK_CHUNK_EMPTY;
+		return result;
+	}
 
 	first = title->data[0];
 	last = title->data[title->len - 1];
@@ -662,7 +671,7 @@ unsigned char *cmark_clean_title(cmark_chunk *title)
 	}
 
 	cmark_strbuf_unescape(&buf);
-	return buf.size == 0 ? NULL : cmark_strbuf_detach(&buf);
+	return cmark_chunk_buf_detach(&buf);
 }
 
 // Parse an autolink or HTML tag.
@@ -766,7 +775,7 @@ static cmark_node* handle_close_bracket(subject* subj, cmark_node *parent)
 	cmark_reference *ref;
 	bool is_image = false;
 	cmark_chunk url_chunk, title_chunk;
-	unsigned char *url, *title;
+	cmark_chunk url, title;
 	delimiter *opener;
 	cmark_node *link_text;
 	cmark_node *inl;
@@ -854,8 +863,8 @@ static cmark_node* handle_close_bracket(subject* subj, cmark_node *parent)
 	cmark_chunk_free(&raw_label);
 
 	if (ref != NULL) { // found
-		url = bufdup(ref->url);
-		title = bufdup(ref->title);
+		url   = chunk_clone(&ref->url);
+		title = chunk_clone(&ref->title);
 		goto match;
 	} else {
 		goto noMatch;
diff --git a/src/inlines.h b/src/inlines.h
@@ -5,8 +5,8 @@
 extern "C" {
 #endif
 
-unsigned char *cmark_clean_url(cmark_chunk *url);
-unsigned char *cmark_clean_title(cmark_chunk *title);
+cmark_chunk cmark_clean_url(cmark_chunk *url);
+cmark_chunk cmark_clean_title(cmark_chunk *title);
 
 void cmark_parse_inlines(cmark_node* parent, cmark_reference_map *refmap, int options);
 
diff --git a/src/node.c b/src/node.c
@@ -122,12 +122,8 @@ void S_free_nodes(cmark_node *e)
 			break;
 		case NODE_LINK:
 		case NODE_IMAGE:
-			if (e->as.link.url) {
-				free(e->as.link.url);
-			}
-			if (e->as.link.title) {
-				free(e->as.link.title);
-			}
+			cmark_chunk_free(&e->as.link.url);
+			cmark_chunk_free(&e->as.link.title);
 			break;
 		default:
 			break;
@@ -282,15 +278,6 @@ cmark_node_set_user_data(cmark_node *node, void *user_data)
 	return 1;
 }
 
-static char*
-S_strdup(const char *str)
-{
-	size_t size = strlen(str) + 1;
-	char *dup = (char *)malloc(size);
-	memcpy(dup, str, size);
-	return dup;
-}
-
 const char*
 cmark_node_get_literal(cmark_node *node)
 {
@@ -541,7 +528,7 @@ cmark_node_get_url(cmark_node *node)
 	switch (node->type) {
 	case NODE_LINK:
 	case NODE_IMAGE:
-		return (char *)node->as.link.url;
+		return cmark_chunk_to_cstr(&node->as.link.url);
 	default:
 		break;
 	}
@@ -559,8 +546,7 @@ cmark_node_set_url(cmark_node *node, const char *url)
 	switch (node->type) {
 	case NODE_LINK:
 	case NODE_IMAGE:
-		free(node->as.link.url);
-		node->as.link.url = (unsigned char *)S_strdup(url);
+		cmark_chunk_set_cstr(&node->as.link.url, url);
 		return 1;
 	default:
 		break;
@@ -579,7 +565,7 @@ cmark_node_get_title(cmark_node *node)
 	switch (node->type) {
 	case NODE_LINK:
 	case NODE_IMAGE:
-		return (char *)node->as.link.title;
+		return cmark_chunk_to_cstr(&node->as.link.title);
 	default:
 		break;
 	}
@@ -597,8 +583,7 @@ cmark_node_set_title(cmark_node *node, const char *title)
 	switch (node->type) {
 	case NODE_LINK:
 	case NODE_IMAGE:
-		free(node->as.link.title);
-		node->as.link.title = (unsigned char *)S_strdup(title);
+		cmark_chunk_set_cstr(&node->as.link.title, title);
 		return 1;
 	default:
 		break;
diff --git a/src/node.h b/src/node.h
@@ -38,8 +38,8 @@ typedef struct {
 } cmark_header;
 
 typedef struct {
-	unsigned char *url;
-	unsigned char *title;
+	cmark_chunk url;
+	cmark_chunk title;
 } cmark_link;
 
 struct cmark_node {
diff --git a/src/references.c b/src/references.c
@@ -20,8 +20,8 @@ static void reference_free(cmark_reference *ref)
 {
 	if(ref != NULL) {
 		free(ref->label);
-		free(ref->url);
-		free(ref->title);
+		cmark_chunk_free(&ref->url);
+		cmark_chunk_free(&ref->title);
 		free(ref);
 	}
 }
diff --git a/src/references.h b/src/references.h
@@ -12,8 +12,8 @@ extern "C" {
 struct cmark_reference {
 	struct cmark_reference *next;
 	unsigned char *label;
-	unsigned char *url;
-	unsigned char *title;
+	cmark_chunk url;
+	cmark_chunk title;
 	unsigned int hash;
 };
 
diff --git a/src/xml.c b/src/xml.c
@@ -118,10 +118,12 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
 		case CMARK_NODE_LINK:
 		case CMARK_NODE_IMAGE:
 			cmark_strbuf_puts(xml, " destination=\"");
-			escape_xml(xml, node->as.link.url, -1);
+			escape_xml(xml, node->as.link.url.data,
+				   node->as.link.url.len);
 			cmark_strbuf_putc(xml, '"');
 			cmark_strbuf_puts(xml, " title=\"");
-			escape_xml(xml, node->as.link.title, -1);
+			escape_xml(xml, node->as.link.title.data,
+				   node->as.link.title.len);
 			cmark_strbuf_putc(xml, '"');
 			break;
 		default: