From cb32c56abbc1e085025da1cd55b151ffb5a006cc Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 28 Mar 2015 23:23:03 -0700 Subject: commonmark rendere: more fine-grained control over escaping. --- src/commonmark.c | 64 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/commonmark.c b/src/commonmark.c index 6347bb5..667e8d2 100644 --- a/src/commonmark.c +++ b/src/commonmark.c @@ -39,24 +39,39 @@ static inline void blankline(struct render_state *state) } } +typedef enum { + NO_ESCAPING, + NORMAL_ESCAPING, + QUOTE_ESCAPING +} escaping; + static inline bool -needs_escaping(int32_t c, unsigned char next_c, struct render_state *state) +needs_escaping(escaping escape, + int32_t c, + unsigned char next_c, + struct render_state *state) { - return (c == '*' || c == '_' || c == '[' || c == ']' || - c == '<' || c == '>' || c == '\\' || - (c == '&' && isalpha(next_c)) || - (c == '!' && next_c == '[') || - (state->begin_line && - (c == '-' || c == '+' || c == '#' || c == '=')) || - (c == '#' && (isspace(next_c) || next_c == '\0')) || - ((c == '.' || c == ')') && - isdigit(state->buffer->ptr[state->buffer->size - 1]))); + if (escape == NORMAL_ESCAPING) { + return (c == '*' || c == '_' || c == '[' || c == ']' || + c == '<' || c == '>' || c == '\\' || + (c == '&' && isalpha(next_c)) || + (c == '!' && next_c == '[') || + (state->begin_line && + (c == '-' || c == '+' || c == '#' || c == '=')) || + (c == '#' && (isspace(next_c) || next_c == '\0')) || + ((c == '.' || c == ')') && + isdigit(state->buffer->ptr[state->buffer->size - 1]))); + } else if (escape == QUOTE_ESCAPING) { + return (c == '"' || c == '\\'); + } else { + return false; + } } static inline void out(struct render_state *state, cmark_chunk str, bool wrap, - bool escape) + escaping escape) { unsigned char* source = str.data; int length = str.len; @@ -115,8 +130,7 @@ static inline void out(struct render_state *state, state->column = 0; state->begin_line = true; state->last_breakable = 0; - } else if (escape && - needs_escaping(c, nextc, state)) { + } else if (needs_escaping(escape, c, nextc, state)) { cmark_strbuf_putc(state->buffer, '\\'); utf8proc_encode_char(c, state->buffer); state->column += 2; @@ -156,7 +170,7 @@ static inline void out(struct render_state *state, static void lit(struct render_state *state, char *s, bool wrap) { cmark_chunk str = cmark_chunk_literal(s); - out(state, str, wrap, false); + out(state, str, wrap, NO_ESCAPING); } static int @@ -282,7 +296,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type, // use indented form if no info lit(state, " ", false); cmark_strbuf_puts(state->prefix, " "); - out(state, node->as.code.literal, false, false); + out(state, node->as.code.literal, false, NO_ESCAPING); cmark_strbuf_truncate(state->prefix, state->prefix->size - 4); } else { @@ -295,9 +309,9 @@ S_render_node(cmark_node *node, cmark_event_type ev_type, lit(state, "`", false); } lit(state, " ", false); - out(state, cmark_chunk_literal(info), false, false); + out(state, cmark_chunk_literal(info), false, NO_ESCAPING); cr(state); - out(state, node->as.code.literal, false, true); + out(state, node->as.code.literal, false, NORMAL_ESCAPING); cr(state); for (i = 0; i < numticks; i++) { lit(state, "`", false); @@ -308,7 +322,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type, case CMARK_NODE_HTML: blankline(state); - out(state, node->as.literal, false, false); + out(state, node->as.literal, false, NO_ESCAPING); blankline(state); break; @@ -325,7 +339,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type, break; case CMARK_NODE_TEXT: - out(state, node->as.literal, true, true); + out(state, node->as.literal, true, NORMAL_ESCAPING); break; case CMARK_NODE_LINEBREAK: @@ -347,7 +361,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type, if (numticks > 1) { lit(state, " ", false); } - out(state, node->as.literal, true, false); + out(state, node->as.literal, true, NO_ESCAPING); if (numticks > 1) { lit(state, " ", false); } @@ -357,7 +371,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type, break; case CMARK_NODE_INLINE_HTML: - out(state, node->as.literal, true, false); + out(state, node->as.literal, true, NO_ESCAPING); break; case CMARK_NODE_STRONG: @@ -384,11 +398,11 @@ S_render_node(cmark_node *node, cmark_event_type ev_type, // TODO - backslash-escape " and \ inside url, title // for both links and images lit(state, "](", false); - out(state, cmark_chunk_literal(cmark_node_get_url(node)), false, true); + out(state, cmark_chunk_literal(cmark_node_get_url(node)), false, QUOTE_ESCAPING); title = cmark_node_get_title(node); if (title && strlen(title) > 0) { lit(state, " \"", true); - out(state, cmark_chunk_literal(title), false, true); + out(state, cmark_chunk_literal(title), false, QUOTE_ESCAPING); lit(state, "\"", false); } lit(state, ")", false); @@ -400,11 +414,11 @@ S_render_node(cmark_node *node, cmark_event_type ev_type, lit(state, "![", false); } else { lit(state, "](", false); - out(state, cmark_chunk_literal(cmark_node_get_url(node)), false, true); + out(state, cmark_chunk_literal(cmark_node_get_url(node)), false, QUOTE_ESCAPING); title = cmark_node_get_title(node); if (title && strlen(title) > 0) { lit(state, " \"", true); - out(state, cmark_chunk_literal(title), false, true); + out(state, cmark_chunk_literal(title), false, QUOTE_ESCAPING); lit(state, "\"", false); } lit(state, ")", false); -- cgit v1.2.3