commonmarker 0.9.2 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of commonmarker might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/ext/commonmarker/cmark/CMakeLists.txt +10 -2
- data/ext/commonmarker/cmark/Makefile +11 -13
- data/ext/commonmarker/cmark/README.md +1 -1
- data/ext/commonmarker/cmark/api_test/main.c +18 -14
- data/ext/commonmarker/cmark/build/CMakeCache.txt +8 -8
- data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CMakeCCompiler.cmake +0 -0
- data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CMakeCXXCompiler.cmake +0 -0
- data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CMakeDetermineCompilerABI_C.bin +0 -0
- data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CMakeDetermineCompilerABI_CXX.bin +0 -0
- data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CMakeSystem.cmake +0 -0
- data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CompilerIdC/CMakeCCompilerId.c +26 -9
- data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CompilerIdC/a.out +0 -0
- data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CompilerIdCXX/CMakeCXXCompilerId.cpp +3 -3
- data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CompilerIdCXX/a.out +0 -0
- data/ext/commonmarker/cmark/build/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
- data/ext/commonmarker/cmark/build/CMakeFiles/CMakeError.log +6 -6
- data/ext/commonmarker/cmark/build/CMakeFiles/CMakeOutput.log +143 -143
- data/ext/commonmarker/cmark/build/CMakeFiles/Makefile.cmake +108 -107
- data/ext/commonmarker/cmark/build/CMakeFiles/Makefile2 +3 -3
- data/ext/commonmarker/cmark/build/Makefile +10 -10
- data/ext/commonmarker/cmark/build/api_test/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
- data/ext/commonmarker/cmark/build/api_test/CMakeFiles/api_test.dir/build.make +4 -4
- data/ext/commonmarker/cmark/build/api_test/CMakeFiles/api_test.dir/flags.make +1 -1
- data/ext/commonmarker/cmark/build/api_test/CMakeFiles/api_test.dir/link.txt +1 -1
- data/ext/commonmarker/cmark/build/api_test/Makefile +10 -10
- data/ext/commonmarker/cmark/build/man/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
- data/ext/commonmarker/cmark/build/man/Makefile +10 -10
- data/ext/commonmarker/cmark/build/man/cmake_install.cmake +2 -2
- data/ext/commonmarker/cmark/build/src/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/Export/lib/cmake/cmark-release.cmake +38 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/Export/lib/cmake/cmark.cmake +92 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/cmark.dir/build.make +3 -3
- data/ext/commonmarker/cmark/build/src/CMakeFiles/cmark.dir/flags.make +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/DependInfo.cmake +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/build.make +26 -26
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/cmake_clean.cmake +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/flags.make +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/link.txt +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/C.includecache +0 -4
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/blocks.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/build.make +3 -3
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/cmark.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/depend.internal +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/depend.make +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/flags.make +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/inlines.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/node.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/references.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/scanners.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/Makefile +10 -10
- data/ext/commonmarker/cmark/build/src/cmake_install.cmake +26 -7
- data/ext/commonmarker/cmark/build/src/cmark_export.h +4 -3
- data/ext/commonmarker/cmark/build/src/cmark_version.h +2 -2
- data/ext/commonmarker/cmark/build/src/config.h +0 -8
- data/ext/commonmarker/cmark/build/src/libcmark.a +0 -0
- data/ext/commonmarker/cmark/build/src/libcmark.pc +1 -1
- data/ext/commonmarker/cmark/build/testdir/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
- data/ext/commonmarker/cmark/build/testdir/Makefile +10 -10
- data/ext/commonmarker/cmark/changelog.txt +111 -0
- data/ext/commonmarker/cmark/man/man3/cmark.3 +26 -26
- data/ext/commonmarker/cmark/src/CMakeLists.txt +3 -0
- data/ext/commonmarker/cmark/src/blocks.c +50 -37
- data/ext/commonmarker/cmark/src/buffer.c +5 -5
- data/ext/commonmarker/cmark/src/buffer.h +4 -2
- data/ext/commonmarker/cmark/src/chunk.h +8 -5
- data/ext/commonmarker/cmark/src/cmark.c +5 -3
- data/ext/commonmarker/cmark/src/cmark.h +7 -6
- data/ext/commonmarker/cmark/src/commonmark.c +8 -10
- data/ext/commonmarker/cmark/src/config.h.in +0 -8
- data/ext/commonmarker/cmark/src/inlines.c +93 -45
- data/ext/commonmarker/cmark/src/inlines.h +2 -2
- data/ext/commonmarker/cmark/src/node.c +0 -3
- data/ext/commonmarker/cmark/src/references.c +3 -2
- data/ext/commonmarker/cmark/src/render.c +6 -5
- data/ext/commonmarker/cmark/src/scanners.c +1050 -1053
- data/ext/commonmarker/cmark/src/scanners.re +4 -4
- data/ext/commonmarker/cmark/test/pathological_tests.py +1 -1
- data/ext/commonmarker/cmark/test/spec.txt +179 -196
- data/lib/commonmarker/version.rb +1 -1
- data/test/test_attributes.rb +1 -1
- metadata +13 -11
@@ -126,6 +126,7 @@ endif(MSVC)
|
|
126
126
|
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON)
|
127
127
|
include (InstallRequiredSystemLibraries)
|
128
128
|
install(TARGETS ${PROGRAM} ${LIBRARY} ${STATICLIBRARY}
|
129
|
+
EXPORT cmark
|
129
130
|
RUNTIME DESTINATION bin
|
130
131
|
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
|
131
132
|
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
|
@@ -138,6 +139,8 @@ install(FILES
|
|
138
139
|
DESTINATION include
|
139
140
|
)
|
140
141
|
|
142
|
+
install(EXPORT cmark DESTINATION ${LIB_INSTALL_DIR}/cmake)
|
143
|
+
|
141
144
|
# Feature tests
|
142
145
|
include(CheckIncludeFile)
|
143
146
|
include(CheckCSourceCompiles)
|
@@ -59,8 +59,8 @@ static void S_parser_feed(cmark_parser *parser, const unsigned char *buffer,
|
|
59
59
|
static void S_process_line(cmark_parser *parser, const unsigned char *buffer,
|
60
60
|
bufsize_t bytes);
|
61
61
|
|
62
|
-
static cmark_node *make_block(cmark_mem *mem, cmark_node_type tag,
|
63
|
-
int start_column) {
|
62
|
+
static cmark_node *make_block(cmark_mem *mem, cmark_node_type tag,
|
63
|
+
int start_line, int start_column) {
|
64
64
|
cmark_node *e;
|
65
65
|
|
66
66
|
e = (cmark_node *)mem->calloc(1, sizeof(*e));
|
@@ -222,24 +222,6 @@ static bool ends_with_blank_line(cmark_node *node) {
|
|
222
222
|
return false;
|
223
223
|
}
|
224
224
|
|
225
|
-
// Break out of all containing lists
|
226
|
-
static int break_out_of_lists(cmark_parser *parser, cmark_node **bptr) {
|
227
|
-
cmark_node *container = *bptr;
|
228
|
-
cmark_node *b = parser->root;
|
229
|
-
// find first containing NODE_LIST:
|
230
|
-
while (b && S_type(b) != CMARK_NODE_LIST) {
|
231
|
-
b = b->last_child;
|
232
|
-
}
|
233
|
-
if (b) {
|
234
|
-
while (container && container != b) {
|
235
|
-
container = finalize(parser, container);
|
236
|
-
}
|
237
|
-
finalize(parser, b);
|
238
|
-
*bptr = b->parent;
|
239
|
-
}
|
240
|
-
return 0;
|
241
|
-
}
|
242
|
-
|
243
225
|
static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
|
244
226
|
bufsize_t pos;
|
245
227
|
cmark_node *item;
|
@@ -247,7 +229,8 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
|
|
247
229
|
cmark_node *parent;
|
248
230
|
|
249
231
|
parent = b->parent;
|
250
|
-
assert(b->flags &
|
232
|
+
assert(b->flags &
|
233
|
+
CMARK_NODE__OPEN); // shouldn't call finalize on closed blocks
|
251
234
|
b->flags &= ~CMARK_NODE__OPEN;
|
252
235
|
|
253
236
|
if (parser->curline.size == 0) {
|
@@ -361,7 +344,8 @@ static cmark_node *add_child(cmark_parser *parser, cmark_node *parent,
|
|
361
344
|
parent = finalize(parser, parent);
|
362
345
|
}
|
363
346
|
|
364
|
-
cmark_node *child =
|
347
|
+
cmark_node *child =
|
348
|
+
make_block(parser->mem, block_type, parser->line_number, start_column);
|
365
349
|
child->parent = parent;
|
366
350
|
|
367
351
|
if (parent->last_child) {
|
@@ -377,8 +361,8 @@ static cmark_node *add_child(cmark_parser *parser, cmark_node *parent,
|
|
377
361
|
|
378
362
|
// Walk through node and all children, recursively, parsing
|
379
363
|
// string content into inline content where appropriate.
|
380
|
-
static void process_inlines(cmark_mem *mem, cmark_node *root,
|
381
|
-
int options) {
|
364
|
+
static void process_inlines(cmark_mem *mem, cmark_node *root,
|
365
|
+
cmark_reference_map *refmap, int options) {
|
382
366
|
cmark_iter *iter = cmark_iter_new(root);
|
383
367
|
cmark_node *cur;
|
384
368
|
cmark_event_type ev_type;
|
@@ -398,11 +382,13 @@ static void process_inlines(cmark_mem *mem, cmark_node *root, cmark_reference_ma
|
|
398
382
|
// Attempts to parse a list item marker (bullet or enumerated).
|
399
383
|
// On success, returns length of the marker, and populates
|
400
384
|
// data with the details. On failure, returns 0.
|
401
|
-
static bufsize_t parse_list_marker(cmark_mem *mem, cmark_chunk *input,
|
385
|
+
static bufsize_t parse_list_marker(cmark_mem *mem, cmark_chunk *input,
|
386
|
+
bufsize_t pos, bool interrupts_paragraph,
|
402
387
|
cmark_list **dataptr) {
|
403
388
|
unsigned char c;
|
404
389
|
bufsize_t startpos;
|
405
390
|
cmark_list *data;
|
391
|
+
bufsize_t i;
|
406
392
|
|
407
393
|
startpos = pos;
|
408
394
|
c = peek_at(input, pos);
|
@@ -412,6 +398,18 @@ static bufsize_t parse_list_marker(cmark_mem *mem, cmark_chunk *input, bufsize_t
|
|
412
398
|
if (!cmark_isspace(peek_at(input, pos))) {
|
413
399
|
return 0;
|
414
400
|
}
|
401
|
+
|
402
|
+
if (interrupts_paragraph) {
|
403
|
+
i = pos;
|
404
|
+
// require non-blank content after list marker:
|
405
|
+
while (S_is_space_or_tab(peek_at(input, i))) {
|
406
|
+
i++;
|
407
|
+
}
|
408
|
+
if (peek_at(input, i) == '\n') {
|
409
|
+
return 0;
|
410
|
+
}
|
411
|
+
}
|
412
|
+
|
415
413
|
data = (cmark_list *)mem->calloc(1, sizeof(*data));
|
416
414
|
data->marker_offset = 0; // will be adjusted later
|
417
415
|
data->list_type = CMARK_BULLET_LIST;
|
@@ -432,12 +430,26 @@ static bufsize_t parse_list_marker(cmark_mem *mem, cmark_chunk *input, bufsize_t
|
|
432
430
|
// This also seems to be the limit for 'start' in some browsers.
|
433
431
|
} while (digits < 9 && cmark_isdigit(peek_at(input, pos)));
|
434
432
|
|
433
|
+
if (interrupts_paragraph && start != 1) {
|
434
|
+
return 0;
|
435
|
+
}
|
435
436
|
c = peek_at(input, pos);
|
436
437
|
if (c == '.' || c == ')') {
|
437
438
|
pos++;
|
438
439
|
if (!cmark_isspace(peek_at(input, pos))) {
|
439
440
|
return 0;
|
440
441
|
}
|
442
|
+
if (interrupts_paragraph) {
|
443
|
+
// require non-blank content after list marker:
|
444
|
+
i = pos;
|
445
|
+
while (S_is_space_or_tab(peek_at(input, i))) {
|
446
|
+
i++;
|
447
|
+
}
|
448
|
+
if (S_is_line_end_char(peek_at(input, i))) {
|
449
|
+
return 0;
|
450
|
+
}
|
451
|
+
}
|
452
|
+
|
441
453
|
data = (cmark_list *)mem->calloc(1, sizeof(*data));
|
442
454
|
data->marker_offset = 0; // will be adjusted later
|
443
455
|
data->list_type = CMARK_ORDERED_LIST;
|
@@ -655,7 +667,8 @@ static void S_advance_offset(cmark_parser *parser, cmark_chunk *input,
|
|
655
667
|
}
|
656
668
|
|
657
669
|
static bool S_last_child_is_open(cmark_node *container) {
|
658
|
-
return container->last_child &&
|
670
|
+
return container->last_child &&
|
671
|
+
(container->last_child->flags & CMARK_NODE__OPEN);
|
659
672
|
}
|
660
673
|
|
661
674
|
static bool parse_block_quote_prefix(cmark_parser *parser, cmark_chunk *input) {
|
@@ -849,6 +862,8 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
|
|
849
862
|
|
850
863
|
if (!indented && peek_at(input, parser->first_nonspace) == '>') {
|
851
864
|
|
865
|
+
bufsize_t blockquote_startpos = parser->first_nonspace;
|
866
|
+
|
852
867
|
S_advance_offset(parser, input,
|
853
868
|
parser->first_nonspace + 1 - parser->offset, false);
|
854
869
|
// optional following character
|
@@ -856,18 +871,19 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
|
|
856
871
|
S_advance_offset(parser, input, 1, true);
|
857
872
|
}
|
858
873
|
*container = add_child(parser, *container, CMARK_NODE_BLOCK_QUOTE,
|
859
|
-
|
874
|
+
blockquote_startpos + 1);
|
860
875
|
|
861
876
|
} else if (!indented && (matched = scan_atx_heading_start(
|
862
877
|
input, parser->first_nonspace))) {
|
863
878
|
bufsize_t hashpos;
|
864
879
|
int level = 0;
|
880
|
+
bufsize_t heading_startpos = parser->first_nonspace;
|
865
881
|
|
866
882
|
S_advance_offset(parser, input,
|
867
883
|
parser->first_nonspace + matched - parser->offset,
|
868
884
|
false);
|
869
|
-
*container =
|
870
|
-
|
885
|
+
*container = add_child(parser, *container, CMARK_NODE_HEADING,
|
886
|
+
heading_startpos + 1);
|
871
887
|
|
872
888
|
hashpos = cmark_chunk_strchr(input, '#', parser->first_nonspace);
|
873
889
|
|
@@ -917,9 +933,11 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
|
|
917
933
|
*container = add_child(parser, *container, CMARK_NODE_THEMATIC_BREAK,
|
918
934
|
parser->first_nonspace + 1);
|
919
935
|
S_advance_offset(parser, input, input->len - 1 - parser->offset, false);
|
920
|
-
} else if ((matched =
|
921
|
-
|
936
|
+
} else if ((matched = parse_list_marker(
|
937
|
+
parser->mem, input, parser->first_nonspace,
|
938
|
+
(*container)->type == CMARK_NODE_PARAGRAPH, &data)) &&
|
922
939
|
(!indented || cont_type == CMARK_NODE_LIST)) {
|
940
|
+
|
923
941
|
// Note that we can have new list items starting with >= 4
|
924
942
|
// spaces indent, as long as the list container is still open.
|
925
943
|
int i = 0;
|
@@ -1015,8 +1033,7 @@ static void add_text_to_container(cmark_parser *parser, cmark_node *container,
|
|
1015
1033
|
const cmark_node_type ctype = S_type(container);
|
1016
1034
|
const bool last_line_blank =
|
1017
1035
|
(parser->blank && ctype != CMARK_NODE_BLOCK_QUOTE &&
|
1018
|
-
ctype != CMARK_NODE_HEADING &&
|
1019
|
-
ctype != CMARK_NODE_THEMATIC_BREAK &&
|
1036
|
+
ctype != CMARK_NODE_HEADING && ctype != CMARK_NODE_THEMATIC_BREAK &&
|
1020
1037
|
!(ctype == CMARK_NODE_CODE_BLOCK && container->as.code.fenced) &&
|
1021
1038
|
!(ctype == CMARK_NODE_ITEM && container->first_child == NULL &&
|
1022
1039
|
container->start_line == parser->line_number));
|
@@ -1144,10 +1161,6 @@ static void S_process_line(cmark_parser *parser, const unsigned char *buffer,
|
|
1144
1161
|
|
1145
1162
|
container = last_matched_container;
|
1146
1163
|
|
1147
|
-
// check to see if we've hit 2nd blank line, break out of list:
|
1148
|
-
if (parser->blank && S_last_line_blank(container))
|
1149
|
-
break_out_of_lists(parser, &container);
|
1150
|
-
|
1151
1164
|
open_new_blocks(parser, &container, &input, all_matched);
|
1152
1165
|
|
1153
1166
|
add_text_to_container(parser, container, last_matched_container, &input);
|
@@ -21,7 +21,8 @@ unsigned char cmark_strbuf__initbuf[1];
|
|
21
21
|
#define MIN(x, y) ((x < y) ? x : y)
|
22
22
|
#endif
|
23
23
|
|
24
|
-
void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
|
24
|
+
void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
|
25
|
+
bufsize_t initial_size) {
|
25
26
|
buf->mem = mem;
|
26
27
|
buf->asize = 0;
|
27
28
|
buf->size = 0;
|
@@ -50,8 +51,8 @@ void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
|
|
50
51
|
new_size += 1;
|
51
52
|
new_size = (new_size + 7) & ~7;
|
52
53
|
|
53
|
-
buf->ptr = (unsigned char *)buf->mem->realloc(
|
54
|
-
|
54
|
+
buf->ptr = (unsigned char *)buf->mem->realloc(buf->asize ? buf->ptr : NULL,
|
55
|
+
new_size);
|
55
56
|
buf->asize = new_size;
|
56
57
|
}
|
57
58
|
|
@@ -112,8 +113,7 @@ void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
|
|
112
113
|
}
|
113
114
|
|
114
115
|
void cmark_strbuf_puts(cmark_strbuf *buf, const char *string) {
|
115
|
-
cmark_strbuf_put(buf, (const unsigned char *)string,
|
116
|
-
strlen(string));
|
116
|
+
cmark_strbuf_put(buf, (const unsigned char *)string, strlen(string));
|
117
117
|
}
|
118
118
|
|
119
119
|
void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize,
|
@@ -23,7 +23,8 @@ typedef struct {
|
|
23
23
|
|
24
24
|
extern unsigned char cmark_strbuf__initbuf[];
|
25
25
|
|
26
|
-
#define CMARK_BUF_INIT(mem)
|
26
|
+
#define CMARK_BUF_INIT(mem) \
|
27
|
+
{ mem, cmark_strbuf__initbuf, 0, 0 }
|
27
28
|
|
28
29
|
/**
|
29
30
|
* Initialize a cmark_strbuf structure.
|
@@ -31,7 +32,8 @@ extern unsigned char cmark_strbuf__initbuf[];
|
|
31
32
|
* For the cases where CMARK_BUF_INIT cannot be used to do static
|
32
33
|
* initialization.
|
33
34
|
*/
|
34
|
-
void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
|
35
|
+
void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
|
36
|
+
bufsize_t initial_size);
|
35
37
|
|
36
38
|
/**
|
37
39
|
* Grow the buffer to hold at least `target_size` bytes.
|
@@ -57,7 +57,8 @@ static CMARK_INLINE bufsize_t
|
|
57
57
|
return p ? (bufsize_t)(p - ch->data) : ch->len;
|
58
58
|
}
|
59
59
|
|
60
|
-
static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_mem *mem,
|
60
|
+
static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_mem *mem,
|
61
|
+
cmark_chunk *c) {
|
61
62
|
unsigned char *str;
|
62
63
|
|
63
64
|
if (c->alloc) {
|
@@ -74,10 +75,9 @@ static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_mem *mem, cmark_chunk
|
|
74
75
|
return (char *)str;
|
75
76
|
}
|
76
77
|
|
77
|
-
static CMARK_INLINE void cmark_chunk_set_cstr(cmark_mem *mem, cmark_chunk *c,
|
78
|
-
|
79
|
-
|
80
|
-
}
|
78
|
+
static CMARK_INLINE void cmark_chunk_set_cstr(cmark_mem *mem, cmark_chunk *c,
|
79
|
+
const char *str) {
|
80
|
+
unsigned char *old = c->alloc ? c->data : NULL;
|
81
81
|
if (str == NULL) {
|
82
82
|
c->len = 0;
|
83
83
|
c->data = NULL;
|
@@ -88,6 +88,9 @@ static CMARK_INLINE void cmark_chunk_set_cstr(cmark_mem *mem, cmark_chunk *c, co
|
|
88
88
|
c->alloc = 1;
|
89
89
|
memcpy(c->data, str, c->len + 1);
|
90
90
|
}
|
91
|
+
if (old != NULL) {
|
92
|
+
mem->free(old);
|
93
|
+
}
|
91
94
|
}
|
92
95
|
|
93
96
|
static CMARK_INLINE cmark_chunk cmark_chunk_literal(const char *data) {
|
@@ -12,17 +12,19 @@ const char *cmark_version_string() { return CMARK_VERSION_STRING; }
|
|
12
12
|
|
13
13
|
static void *xcalloc(size_t nmem, size_t size) {
|
14
14
|
void *ptr = calloc(nmem, size);
|
15
|
-
if (!ptr)
|
15
|
+
if (!ptr)
|
16
|
+
abort();
|
16
17
|
return ptr;
|
17
18
|
}
|
18
19
|
|
19
20
|
static void *xrealloc(void *ptr, size_t size) {
|
20
21
|
void *new_ptr = realloc(ptr, size);
|
21
|
-
if (!new_ptr)
|
22
|
+
if (!new_ptr)
|
23
|
+
abort();
|
22
24
|
return new_ptr;
|
23
25
|
}
|
24
26
|
|
25
|
-
cmark_mem DEFAULT_MEM_ALLOCATOR = {
|
27
|
+
cmark_mem DEFAULT_MEM_ALLOCATOR = {xcalloc, xrealloc, free};
|
26
28
|
|
27
29
|
char *cmark_markdown_to_html(const char *text, size_t len, int options) {
|
28
30
|
cmark_node *doc;
|
@@ -95,12 +95,11 @@ typedef struct cmark_iter cmark_iter;
|
|
95
95
|
* when parsing and allocating a document tree
|
96
96
|
*/
|
97
97
|
typedef struct cmark_mem {
|
98
|
-
|
99
|
-
|
100
|
-
|
98
|
+
void *(*calloc)(size_t, size_t);
|
99
|
+
void *(*realloc)(void *, size_t);
|
100
|
+
void (*free)(void *);
|
101
101
|
} cmark_mem;
|
102
102
|
|
103
|
-
|
104
103
|
/**
|
105
104
|
* ## Creating and Destroying Nodes
|
106
105
|
*/
|
@@ -112,9 +111,11 @@ typedef struct cmark_mem {
|
|
112
111
|
CMARK_EXPORT cmark_node *cmark_node_new(cmark_node_type type);
|
113
112
|
|
114
113
|
/** Same as `cmark_node_new`, but explicitly listing the memory
|
115
|
-
* allocator used to allocate the node
|
114
|
+
* allocator used to allocate the node. Note: be sure to use the same
|
115
|
+
* allocator for every node in a tree, or bad things can happen.
|
116
116
|
*/
|
117
|
-
CMARK_EXPORT cmark_node *cmark_node_new_with_mem(cmark_node_type type,
|
117
|
+
CMARK_EXPORT cmark_node *cmark_node_new_with_mem(cmark_node_type type,
|
118
|
+
cmark_mem *mem);
|
118
119
|
|
119
120
|
/** Frees the memory allocated for a node and any children.
|
120
121
|
*/
|
@@ -29,8 +29,7 @@ static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_escaping escape,
|
|
29
29
|
char encoded[ENCODED_SIZE];
|
30
30
|
|
31
31
|
needs_escaping =
|
32
|
-
c < 0x80 &&
|
33
|
-
escape != LITERAL &&
|
32
|
+
c < 0x80 && escape != LITERAL &&
|
34
33
|
((escape == NORMAL &&
|
35
34
|
(c == '*' || c == '_' || c == '[' || c == ']' || c == '#' || c == '<' ||
|
36
35
|
c == '>' || c == '\\' || c == '`' || c == '!' ||
|
@@ -41,9 +40,9 @@ static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_escaping escape,
|
|
41
40
|
!follows_digit) ||
|
42
41
|
(renderer->begin_content && (c == '.' || c == ')') && follows_digit &&
|
43
42
|
(nextc == 0 || cmark_isspace(nextc))))) ||
|
44
|
-
(escape == URL &&
|
45
|
-
|
46
|
-
|
43
|
+
(escape == URL &&
|
44
|
+
(c == '`' || c == '<' || c == '>' || cmark_isspace(c) || c == '\\' ||
|
45
|
+
c == ')' || c == '(')) ||
|
47
46
|
(escape == TITLE &&
|
48
47
|
(c == '`' || c == '<' || c == '>' || c == '"' || c == '\\')));
|
49
48
|
|
@@ -268,7 +267,7 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
|
268
267
|
|
269
268
|
case CMARK_NODE_CODE_BLOCK:
|
270
269
|
first_in_list_item = node->prev == NULL && node->parent &&
|
271
|
-
|
270
|
+
node->parent->type == CMARK_NODE_ITEM;
|
272
271
|
|
273
272
|
if (!first_in_list_item) {
|
274
273
|
BLANKLINE();
|
@@ -348,10 +347,9 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
|
348
347
|
if (CMARK_OPT_HARDBREAKS & options) {
|
349
348
|
LIT(" ");
|
350
349
|
CR();
|
351
|
-
} else if (!renderer->no_linebreaks &&
|
352
|
-
|
353
|
-
|
354
|
-
!(CMARK_OPT_NOBREAKS & options)) {
|
350
|
+
} else if (!renderer->no_linebreaks && renderer->width == 0 &&
|
351
|
+
!(CMARK_OPT_HARDBREAKS & options) &&
|
352
|
+
!(CMARK_OPT_NOBREAKS & options)) {
|
355
353
|
CR();
|
356
354
|
} else {
|
357
355
|
OUT(" ", allow_wrap, LITERAL);
|
@@ -69,14 +69,6 @@ CMARK_INLINE int c99_snprintf(char *outBuf, size_t size, const char *format, ...
|
|
69
69
|
|
70
70
|
#endif
|
71
71
|
|
72
|
-
#ifdef _WIN32
|
73
|
-
# include <BaseTsd.h>
|
74
|
-
typedef SSIZE_T ssize_t;
|
75
|
-
typedef SIZE_T size_t;
|
76
|
-
#else
|
77
|
-
# include <sys/types.h>
|
78
|
-
#endif
|
79
|
-
|
80
72
|
#ifdef __cplusplus
|
81
73
|
}
|
82
74
|
#endif
|
@@ -34,19 +34,28 @@ typedef struct delimiter {
|
|
34
34
|
struct delimiter *previous;
|
35
35
|
struct delimiter *next;
|
36
36
|
cmark_node *inl_text;
|
37
|
-
bufsize_t position;
|
38
37
|
unsigned char delim_char;
|
39
38
|
bool can_open;
|
40
39
|
bool can_close;
|
41
|
-
bool active;
|
42
40
|
} delimiter;
|
43
41
|
|
42
|
+
typedef struct bracket {
|
43
|
+
struct bracket *previous;
|
44
|
+
struct delimiter *previous_delimiter;
|
45
|
+
cmark_node *inl_text;
|
46
|
+
bufsize_t position;
|
47
|
+
bool image;
|
48
|
+
bool active;
|
49
|
+
bool bracket_after;
|
50
|
+
} bracket;
|
51
|
+
|
44
52
|
typedef struct {
|
45
53
|
cmark_mem *mem;
|
46
54
|
cmark_chunk input;
|
47
55
|
bufsize_t pos;
|
48
56
|
cmark_reference_map *refmap;
|
49
57
|
delimiter *last_delim;
|
58
|
+
bracket *last_bracket;
|
50
59
|
} subject;
|
51
60
|
|
52
61
|
static CMARK_INLINE bool S_is_line_end_char(char c) {
|
@@ -63,7 +72,8 @@ static void subject_from_buf(cmark_mem *mem, subject *e, cmark_strbuf *buffer,
|
|
63
72
|
static bufsize_t subject_find_special_char(subject *subj, int options);
|
64
73
|
|
65
74
|
// Create an inline with a literal string value.
|
66
|
-
static CMARK_INLINE cmark_node *make_literal(cmark_mem *mem, cmark_node_type t,
|
75
|
+
static CMARK_INLINE cmark_node *make_literal(cmark_mem *mem, cmark_node_type t,
|
76
|
+
cmark_chunk s) {
|
67
77
|
cmark_node *e = (cmark_node *)mem->calloc(1, sizeof(*e));
|
68
78
|
cmark_strbuf_init(mem, &e->content, 0);
|
69
79
|
e->type = t;
|
@@ -80,7 +90,8 @@ static CMARK_INLINE cmark_node *make_simple(cmark_mem *mem, cmark_node_type t) {
|
|
80
90
|
}
|
81
91
|
|
82
92
|
// Like make_str, but parses entities.
|
83
|
-
static cmark_node *make_str_with_entities(cmark_mem *mem,
|
93
|
+
static cmark_node *make_str_with_entities(cmark_mem *mem,
|
94
|
+
cmark_chunk *content) {
|
84
95
|
cmark_strbuf unescaped = CMARK_BUF_INIT(mem);
|
85
96
|
|
86
97
|
if (houdini_unescape_html(&unescaped, content->data, content->len)) {
|
@@ -105,7 +116,8 @@ static cmark_chunk chunk_clone(cmark_mem *mem, cmark_chunk *src) {
|
|
105
116
|
return c;
|
106
117
|
}
|
107
118
|
|
108
|
-
static cmark_chunk cmark_clean_autolink(cmark_mem *mem, cmark_chunk *url,
|
119
|
+
static cmark_chunk cmark_clean_autolink(cmark_mem *mem, cmark_chunk *url,
|
120
|
+
int is_email) {
|
109
121
|
cmark_strbuf buf = CMARK_BUF_INIT(mem);
|
110
122
|
|
111
123
|
cmark_chunk_trim(url);
|
@@ -122,7 +134,8 @@ static cmark_chunk cmark_clean_autolink(cmark_mem *mem, cmark_chunk *url, int is
|
|
122
134
|
return cmark_chunk_buf_detach(&buf);
|
123
135
|
}
|
124
136
|
|
125
|
-
static CMARK_INLINE cmark_node *make_autolink(cmark_mem *mem, cmark_chunk url,
|
137
|
+
static CMARK_INLINE cmark_node *make_autolink(cmark_mem *mem, cmark_chunk url,
|
138
|
+
int is_email) {
|
126
139
|
cmark_node *link = make_simple(mem, CMARK_NODE_LINK);
|
127
140
|
link->as.link.url = cmark_clean_autolink(mem, &url, is_email);
|
128
141
|
link->as.link.title = cmark_chunk_literal("");
|
@@ -139,6 +152,7 @@ static void subject_from_buf(cmark_mem *mem, subject *e, cmark_strbuf *buffer,
|
|
139
152
|
e->pos = 0;
|
140
153
|
e->refmap = refmap;
|
141
154
|
e->last_delim = NULL;
|
155
|
+
e->last_bracket = NULL;
|
142
156
|
}
|
143
157
|
|
144
158
|
static CMARK_INLINE int isbacktick(int c) { return (c == '`'); }
|
@@ -342,6 +356,15 @@ static void remove_delimiter(subject *subj, delimiter *delim) {
|
|
342
356
|
free(delim);
|
343
357
|
}
|
344
358
|
|
359
|
+
static void pop_bracket(subject *subj) {
|
360
|
+
bracket *b;
|
361
|
+
if (subj->last_bracket == NULL)
|
362
|
+
return;
|
363
|
+
b = subj->last_bracket;
|
364
|
+
subj->last_bracket = subj->last_bracket->previous;
|
365
|
+
free(b);
|
366
|
+
}
|
367
|
+
|
345
368
|
static void push_delimiter(subject *subj, unsigned char c, bool can_open,
|
346
369
|
bool can_close, cmark_node *inl_text) {
|
347
370
|
delimiter *delim = (delimiter *)subj->mem->calloc(1, sizeof(delimiter));
|
@@ -354,11 +377,24 @@ static void push_delimiter(subject *subj, unsigned char c, bool can_open,
|
|
354
377
|
if (delim->previous != NULL) {
|
355
378
|
delim->previous->next = delim;
|
356
379
|
}
|
357
|
-
delim->position = subj->pos;
|
358
|
-
delim->active = true;
|
359
380
|
subj->last_delim = delim;
|
360
381
|
}
|
361
382
|
|
383
|
+
static void push_bracket(subject *subj, bool image, cmark_node *inl_text) {
|
384
|
+
bracket *b = (bracket *)subj->mem->calloc(1, sizeof(bracket));
|
385
|
+
if (subj->last_bracket != NULL) {
|
386
|
+
subj->last_bracket->bracket_after = true;
|
387
|
+
}
|
388
|
+
b->image = image;
|
389
|
+
b->active = true;
|
390
|
+
b->inl_text = inl_text;
|
391
|
+
b->previous = subj->last_bracket;
|
392
|
+
b->previous_delimiter = subj->last_delim;
|
393
|
+
b->position = subj->pos;
|
394
|
+
b->bracket_after = false;
|
395
|
+
subj->last_bracket = b;
|
396
|
+
}
|
397
|
+
|
362
398
|
// Assumes the subject has a c at the current position.
|
363
399
|
static cmark_node *handle_delim(subject *subj, unsigned char c, bool smart) {
|
364
400
|
bufsize_t numdelims;
|
@@ -450,6 +486,7 @@ static void process_emphasis(subject *subj, delimiter *stack_bottom) {
|
|
450
486
|
delimiter *opener;
|
451
487
|
delimiter *old_closer;
|
452
488
|
bool opener_found;
|
489
|
+
bool odd_match;
|
453
490
|
delimiter *openers_bottom[128];
|
454
491
|
|
455
492
|
// initialize openers_bottom:
|
@@ -465,15 +502,22 @@ static void process_emphasis(subject *subj, delimiter *stack_bottom) {
|
|
465
502
|
|
466
503
|
// now move forward, looking for closers, and handling each
|
467
504
|
while (closer != NULL) {
|
468
|
-
if (closer->can_close
|
469
|
-
(closer->delim_char == '*' || closer->delim_char == '_' ||
|
470
|
-
closer->delim_char == '"' || closer->delim_char == '\'')) {
|
505
|
+
if (closer->can_close) {
|
471
506
|
// Now look backwards for first matching opener:
|
472
507
|
opener = closer->previous;
|
473
508
|
opener_found = false;
|
509
|
+
odd_match = false;
|
474
510
|
while (opener != NULL && opener != stack_bottom &&
|
475
511
|
opener != openers_bottom[closer->delim_char]) {
|
476
|
-
|
512
|
+
// interior closer of size 2 can't match opener of size 1
|
513
|
+
// or of size 1 can't match 2
|
514
|
+
odd_match = (closer->can_open || opener->can_close) &&
|
515
|
+
((opener->inl_text->as.literal.len +
|
516
|
+
closer->inl_text->as.literal.len) %
|
517
|
+
3 ==
|
518
|
+
0);
|
519
|
+
if (opener->delim_char == closer->delim_char && opener->can_open &&
|
520
|
+
!odd_match) {
|
477
521
|
opener_found = true;
|
478
522
|
break;
|
479
523
|
}
|
@@ -503,8 +547,12 @@ static void process_emphasis(subject *subj, delimiter *stack_bottom) {
|
|
503
547
|
}
|
504
548
|
closer = closer->next;
|
505
549
|
}
|
506
|
-
if (!opener_found) {
|
507
|
-
// set lower bound for future searches for openers
|
550
|
+
if (!opener_found && !odd_match) {
|
551
|
+
// set lower bound for future searches for openers
|
552
|
+
// (we don't do this with 'odd_match' set because
|
553
|
+
// a ** that didn't match an earlier * might turn into
|
554
|
+
// an opener, and the * might be matched by something
|
555
|
+
// else.
|
508
556
|
openers_bottom[old_closer->delim_char] = old_closer->previous;
|
509
557
|
if (!old_closer->can_open) {
|
510
558
|
// we can remove a closer that can't be an
|
@@ -755,27 +803,21 @@ static cmark_node *handle_close_bracket(subject *subj) {
|
|
755
803
|
bufsize_t starturl, endurl, starttitle, endtitle, endall;
|
756
804
|
bufsize_t n;
|
757
805
|
bufsize_t sps;
|
758
|
-
cmark_reference *ref;
|
759
|
-
bool is_image = false;
|
806
|
+
cmark_reference *ref = NULL;
|
760
807
|
cmark_chunk url_chunk, title_chunk;
|
761
808
|
cmark_chunk url, title;
|
762
|
-
|
809
|
+
bracket *opener;
|
763
810
|
cmark_node *inl;
|
764
811
|
cmark_chunk raw_label;
|
765
812
|
int found_label;
|
766
813
|
cmark_node *tmp, *tmpnext;
|
814
|
+
bool is_image;
|
767
815
|
|
768
816
|
advance(subj); // advance past ]
|
769
817
|
initial_pos = subj->pos;
|
770
818
|
|
771
|
-
//
|
772
|
-
opener = subj->
|
773
|
-
while (opener) {
|
774
|
-
if (opener->delim_char == '[' || opener->delim_char == '!') {
|
775
|
-
break;
|
776
|
-
}
|
777
|
-
opener = opener->previous;
|
778
|
-
}
|
819
|
+
// get last [ or ![
|
820
|
+
opener = subj->last_bracket;
|
779
821
|
|
780
822
|
if (opener == NULL) {
|
781
823
|
return make_str(subj->mem, cmark_chunk_literal("]"));
|
@@ -783,14 +825,13 @@ static cmark_node *handle_close_bracket(subject *subj) {
|
|
783
825
|
|
784
826
|
if (!opener->active) {
|
785
827
|
// take delimiter off stack
|
786
|
-
|
828
|
+
pop_bracket(subj);
|
787
829
|
return make_str(subj->mem, cmark_chunk_literal("]"));
|
788
830
|
}
|
789
831
|
|
790
832
|
// If we got here, we matched a potential link/image text.
|
791
|
-
is_image = opener->delim_char == '!';
|
792
|
-
|
793
833
|
// Now we check to see if it's a link/image.
|
834
|
+
is_image = opener->image;
|
794
835
|
|
795
836
|
// First, look for an inline link.
|
796
837
|
if (peek_char(subj) == '(' &&
|
@@ -830,20 +871,23 @@ static cmark_node *handle_close_bracket(subject *subj) {
|
|
830
871
|
// skip spaces
|
831
872
|
raw_label = cmark_chunk_literal("");
|
832
873
|
found_label = link_label(subj, &raw_label);
|
833
|
-
if (!found_label || raw_label.len == 0) {
|
834
|
-
cmark_chunk_free(subj->mem, &raw_label);
|
835
|
-
raw_label = cmark_chunk_dup(&subj->input, opener->position,
|
836
|
-
initial_pos - opener->position - 1);
|
837
|
-
}
|
838
|
-
|
839
874
|
if (!found_label) {
|
840
875
|
// If we have a shortcut reference link, back up
|
841
876
|
// to before the spacse we skipped.
|
842
877
|
subj->pos = initial_pos;
|
843
878
|
}
|
844
879
|
|
845
|
-
|
846
|
-
|
880
|
+
if ((!found_label || raw_label.len == 0) && !opener->bracket_after) {
|
881
|
+
cmark_chunk_free(subj->mem, &raw_label);
|
882
|
+
raw_label = cmark_chunk_dup(&subj->input, opener->position,
|
883
|
+
initial_pos - opener->position - 1);
|
884
|
+
found_label = true;
|
885
|
+
}
|
886
|
+
|
887
|
+
if (found_label) {
|
888
|
+
ref = cmark_reference_lookup(subj->refmap, &raw_label);
|
889
|
+
cmark_chunk_free(subj->mem, &raw_label);
|
890
|
+
}
|
847
891
|
|
848
892
|
if (ref != NULL) { // found
|
849
893
|
url = chunk_clone(subj->mem, &ref->url);
|
@@ -855,7 +899,7 @@ static cmark_node *handle_close_bracket(subject *subj) {
|
|
855
899
|
|
856
900
|
noMatch:
|
857
901
|
// If we fall through to here, it means we didn't match a link:
|
858
|
-
|
902
|
+
pop_bracket(subj); // remove this opener from delimiter list
|
859
903
|
subj->pos = initial_pos;
|
860
904
|
return make_str(subj->mem, cmark_chunk_literal("]"));
|
861
905
|
|
@@ -875,16 +919,16 @@ match:
|
|
875
919
|
// Free the bracket [:
|
876
920
|
cmark_node_free(opener->inl_text);
|
877
921
|
|
878
|
-
process_emphasis(subj, opener);
|
922
|
+
process_emphasis(subj, opener->previous_delimiter);
|
923
|
+
pop_bracket(subj);
|
879
924
|
|
880
925
|
// Now, if we have a link, we also want to deactivate earlier link
|
881
926
|
// delimiters. (This code can be removed if we decide to allow links
|
882
927
|
// inside links.)
|
883
|
-
remove_delimiter(subj, opener);
|
884
928
|
if (!is_image) {
|
885
|
-
opener = subj->
|
929
|
+
opener = subj->last_bracket;
|
886
930
|
while (opener != NULL) {
|
887
|
-
if (opener->
|
931
|
+
if (!opener->image) {
|
888
932
|
if (!opener->active) {
|
889
933
|
break;
|
890
934
|
} else {
|
@@ -1005,7 +1049,7 @@ static int parse_inline(subject *subj, cmark_node *parent, int options) {
|
|
1005
1049
|
case '[':
|
1006
1050
|
advance(subj);
|
1007
1051
|
new_inl = make_str(subj->mem, cmark_chunk_literal("["));
|
1008
|
-
|
1052
|
+
push_bracket(subj, false, new_inl);
|
1009
1053
|
break;
|
1010
1054
|
case ']':
|
1011
1055
|
new_inl = handle_close_bracket(subj);
|
@@ -1015,7 +1059,7 @@ static int parse_inline(subject *subj, cmark_node *parent, int options) {
|
|
1015
1059
|
if (peek_char(subj) == '[') {
|
1016
1060
|
advance(subj);
|
1017
1061
|
new_inl = make_str(subj->mem, cmark_chunk_literal("!["));
|
1018
|
-
|
1062
|
+
push_bracket(subj, true, new_inl);
|
1019
1063
|
} else {
|
1020
1064
|
new_inl = make_str(subj->mem, cmark_chunk_literal("!"));
|
1021
1065
|
}
|
@@ -1040,8 +1084,8 @@ static int parse_inline(subject *subj, cmark_node *parent, int options) {
|
|
1040
1084
|
}
|
1041
1085
|
|
1042
1086
|
// Parse inlines from parent's string_content, adding as children of parent.
|
1043
|
-
extern void cmark_parse_inlines(cmark_mem *mem, cmark_node *parent,
|
1044
|
-
int options) {
|
1087
|
+
extern void cmark_parse_inlines(cmark_mem *mem, cmark_node *parent,
|
1088
|
+
cmark_reference_map *refmap, int options) {
|
1045
1089
|
subject subj;
|
1046
1090
|
subject_from_buf(mem, &subj, &parent->content, refmap);
|
1047
1091
|
cmark_chunk_rtrim(&subj.input);
|
@@ -1050,6 +1094,10 @@ extern void cmark_parse_inlines(cmark_mem *mem, cmark_node *parent, cmark_refere
|
|
1050
1094
|
;
|
1051
1095
|
|
1052
1096
|
process_emphasis(&subj, NULL);
|
1097
|
+
// free bracket stack
|
1098
|
+
while (subj.last_bracket) {
|
1099
|
+
pop_bracket(&subj);
|
1100
|
+
}
|
1053
1101
|
}
|
1054
1102
|
|
1055
1103
|
// Parse zero or more space characters, including at most one newline.
|