Handle escape sequences in link titles.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
diff --git a/md4c/md4c.c b/md4c/md4c.c
index 48285ff..9409db9 100644
--- a/md4c/md4c.c
+++ b/md4c/md4c.c
@@ -1370,7 +1370,8 @@ md_is_link_destination(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end,
static int
md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
OFF* p_end, int* p_beg_line_index, int* p_end_line_index,
- OFF* p_contents_beg, OFF* p_contents_end)
+ OFF* p_contents_beg, OFF* p_contents_end,
+ int* p_has_escape)
{
OFF off = beg;
CHAR closer_char;
@@ -1398,12 +1399,14 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
off++;
*p_contents_beg = off;
+ *p_has_escape = FALSE;
while(line_index < n_lines) {
OFF line_end = lines[line_index].end;
while(off < line_end) {
if(CH(off) == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) {
+ *p_has_escape = TRUE;
off++;
} else if(CH(off) == closer_char) {
/* Success. */
@@ -1423,11 +1426,13 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
}
/* Allocate new buffer, and fill it with copy of the string between
- * 'beg' and 'end' but replace any line breaks with single space.
+ * 'beg' and 'end' but replace any line breaks with given replacement character
+ * and also optionally resolve any escape sequences.
*/
static int
-md_remove_line_breaks(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, int n_lines,
- CHAR replacement_char, CHAR** p_str, SZ* p_size)
+md_normalize_string(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, int n_lines,
+ CHAR line_break_replacement_char, int resolve_escapes,
+ CHAR** p_str, SZ* p_size)
{
CHAR* buffer;
CHAR* ptr;
@@ -1452,13 +1457,18 @@ md_remove_line_breaks(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, int n
return 0;
}
- *ptr = CH(off);
- ptr++;
-
- off++;
+ if(resolve_escapes && CH(off) == _T('\\') &&
+ off+1 < end && (ISPUNCT(off+1) || ISNEWLINE(off+1)))
+ {
+ off++;
+ } else {
+ *ptr = CH(off);
+ ptr++;
+ off++;
+ }
}
- *ptr = replacement_char;
+ *ptr = line_break_replacement_char;
ptr++;
line_index++;
@@ -1488,6 +1498,7 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
OFF title_contents_end;
int title_contents_line_index;
int title_is_multiline;
+ int title_has_escape;
OFF off;
int line_index = 0;
int tmp_line_index;
@@ -1525,7 +1536,7 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
* more follows on its last line. */
if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off,
&off, &title_contents_line_index, &tmp_line_index,
- &title_contents_beg, &title_contents_end)
+ &title_contents_beg, &title_contents_end, &title_has_escape)
&& off >= lines[line_index + tmp_line_index].end)
{
title_is_multiline = (tmp_line_index != title_contents_line_index);
@@ -1568,9 +1579,9 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
} else {
SZ label_size;
- MD_CHECK(md_remove_line_breaks(ctx, label_contents_beg, label_contents_end,
+ MD_CHECK(md_normalize_string(ctx, label_contents_beg, label_contents_end,
lines + label_contents_line_index, n_lines - label_contents_line_index,
- _T(' '), &def->label, &label_size));
+ _T(' '), FALSE, &def->label, &label_size));
def->label_size = label_size;
def->label_needs_free = TRUE;
}
@@ -1582,13 +1593,13 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
if(title_contents_beg >= title_contents_end) {
def->title = NULL;
def->title_size = 0;
- } else if(!title_is_multiline) {
+ } else if(!title_is_multiline && !title_has_escape) {
def->title = (CHAR*) STR(title_contents_beg);
def->title_size = title_contents_end - title_contents_beg;
} else {
- MD_CHECK(md_remove_line_breaks(ctx, title_contents_beg, title_contents_end,
+ MD_CHECK(md_normalize_string(ctx, title_contents_beg, title_contents_end,
lines + title_contents_line_index, n_lines - title_contents_line_index,
- _T('\n'), &def->title, &def->title_size));
+ _T('\n'), TRUE, &def->title, &def->title_size));
def->title_needs_free = TRUE;
}
@@ -1722,8 +1733,8 @@ md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
end_line++;
if(beg_line != end_line) {
- MD_CHECK(md_remove_line_breaks(ctx, beg, end, beg_line,
- n_lines - (beg_line - lines), _T(' '), &label, &label_size));
+ MD_CHECK(md_normalize_string(ctx, beg, end, beg_line,
+ n_lines - (beg_line - lines), _T(' '), FALSE, &label, &label_size));
} else {
label = (CHAR*) STR(beg);
label_size = end - beg;
@@ -1756,6 +1767,7 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
OFF title_contents_end;
int title_contents_line_index;
int title_is_multiline;
+ int title_has_escape;
OFF off = beg;
int ret = FALSE;
@@ -1785,7 +1797,7 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
/* (Optional) title. */
if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off,
&off, &title_contents_line_index, &tmp_line_index,
- &title_contents_beg, &title_contents_end))
+ &title_contents_beg, &title_contents_end, &title_has_escape))
{
title_is_multiline = (tmp_line_index != title_contents_line_index);
title_contents_line_index += line_index;
@@ -1815,14 +1827,14 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
attr->title = NULL;
attr->title_size = 0;
attr->title_needs_free = FALSE;
- } else if(!title_is_multiline) {
+ } else if(!title_is_multiline && !title_has_escape) {
attr->title = (CHAR*) STR(title_contents_beg);
attr->title_size = title_contents_end - title_contents_beg;
attr->title_needs_free = FALSE;
} else {
- MD_CHECK(md_remove_line_breaks(ctx, title_contents_beg, title_contents_end,
+ MD_CHECK(md_normalize_string(ctx, title_contents_beg, title_contents_end,
lines + title_contents_line_index, n_lines - title_contents_line_index,
- _T('\n'), &attr->title, &attr->title_size));
+ _T('\n'), TRUE, &attr->title, &attr->title_size));
attr->title_needs_free = TRUE;
}