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.

Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/ext/commonmarker/cmark/CMakeLists.txt +10 -2
  3. data/ext/commonmarker/cmark/Makefile +11 -13
  4. data/ext/commonmarker/cmark/README.md +1 -1
  5. data/ext/commonmarker/cmark/api_test/main.c +18 -14
  6. data/ext/commonmarker/cmark/build/CMakeCache.txt +8 -8
  7. data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CMakeCCompiler.cmake +0 -0
  8. data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CMakeCXXCompiler.cmake +0 -0
  9. data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CMakeDetermineCompilerABI_C.bin +0 -0
  10. data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CMakeDetermineCompilerABI_CXX.bin +0 -0
  11. data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CMakeSystem.cmake +0 -0
  12. data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CompilerIdC/CMakeCCompilerId.c +26 -9
  13. data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CompilerIdC/a.out +0 -0
  14. data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CompilerIdCXX/CMakeCXXCompilerId.cpp +3 -3
  15. data/ext/commonmarker/cmark/build/CMakeFiles/{3.5.2 → 3.6.0}/CompilerIdCXX/a.out +0 -0
  16. data/ext/commonmarker/cmark/build/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  17. data/ext/commonmarker/cmark/build/CMakeFiles/CMakeError.log +6 -6
  18. data/ext/commonmarker/cmark/build/CMakeFiles/CMakeOutput.log +143 -143
  19. data/ext/commonmarker/cmark/build/CMakeFiles/Makefile.cmake +108 -107
  20. data/ext/commonmarker/cmark/build/CMakeFiles/Makefile2 +3 -3
  21. data/ext/commonmarker/cmark/build/Makefile +10 -10
  22. data/ext/commonmarker/cmark/build/api_test/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  23. data/ext/commonmarker/cmark/build/api_test/CMakeFiles/api_test.dir/build.make +4 -4
  24. data/ext/commonmarker/cmark/build/api_test/CMakeFiles/api_test.dir/flags.make +1 -1
  25. data/ext/commonmarker/cmark/build/api_test/CMakeFiles/api_test.dir/link.txt +1 -1
  26. data/ext/commonmarker/cmark/build/api_test/Makefile +10 -10
  27. data/ext/commonmarker/cmark/build/man/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  28. data/ext/commonmarker/cmark/build/man/Makefile +10 -10
  29. data/ext/commonmarker/cmark/build/man/cmake_install.cmake +2 -2
  30. data/ext/commonmarker/cmark/build/src/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  31. data/ext/commonmarker/cmark/build/src/CMakeFiles/Export/lib/cmake/cmark-release.cmake +38 -0
  32. data/ext/commonmarker/cmark/build/src/CMakeFiles/Export/lib/cmake/cmark.cmake +92 -0
  33. data/ext/commonmarker/cmark/build/src/CMakeFiles/cmark.dir/build.make +3 -3
  34. data/ext/commonmarker/cmark/build/src/CMakeFiles/cmark.dir/flags.make +1 -1
  35. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/DependInfo.cmake +1 -1
  36. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/build.make +26 -26
  37. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/cmake_clean.cmake +1 -1
  38. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/flags.make +1 -1
  39. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/link.txt +1 -1
  40. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/C.includecache +0 -4
  41. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/blocks.c.o +0 -0
  42. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/build.make +3 -3
  43. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/cmark.c.o +0 -0
  44. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/depend.internal +1 -1
  45. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/depend.make +1 -1
  46. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/flags.make +1 -1
  47. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/inlines.c.o +0 -0
  48. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/node.c.o +0 -0
  49. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/references.c.o +0 -0
  50. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/scanners.c.o +0 -0
  51. data/ext/commonmarker/cmark/build/src/Makefile +10 -10
  52. data/ext/commonmarker/cmark/build/src/cmake_install.cmake +26 -7
  53. data/ext/commonmarker/cmark/build/src/cmark_export.h +4 -3
  54. data/ext/commonmarker/cmark/build/src/cmark_version.h +2 -2
  55. data/ext/commonmarker/cmark/build/src/config.h +0 -8
  56. data/ext/commonmarker/cmark/build/src/libcmark.a +0 -0
  57. data/ext/commonmarker/cmark/build/src/libcmark.pc +1 -1
  58. data/ext/commonmarker/cmark/build/testdir/CMakeFiles/CMakeDirectoryInformation.cmake +1 -1
  59. data/ext/commonmarker/cmark/build/testdir/Makefile +10 -10
  60. data/ext/commonmarker/cmark/changelog.txt +111 -0
  61. data/ext/commonmarker/cmark/man/man3/cmark.3 +26 -26
  62. data/ext/commonmarker/cmark/src/CMakeLists.txt +3 -0
  63. data/ext/commonmarker/cmark/src/blocks.c +50 -37
  64. data/ext/commonmarker/cmark/src/buffer.c +5 -5
  65. data/ext/commonmarker/cmark/src/buffer.h +4 -2
  66. data/ext/commonmarker/cmark/src/chunk.h +8 -5
  67. data/ext/commonmarker/cmark/src/cmark.c +5 -3
  68. data/ext/commonmarker/cmark/src/cmark.h +7 -6
  69. data/ext/commonmarker/cmark/src/commonmark.c +8 -10
  70. data/ext/commonmarker/cmark/src/config.h.in +0 -8
  71. data/ext/commonmarker/cmark/src/inlines.c +93 -45
  72. data/ext/commonmarker/cmark/src/inlines.h +2 -2
  73. data/ext/commonmarker/cmark/src/node.c +0 -3
  74. data/ext/commonmarker/cmark/src/references.c +3 -2
  75. data/ext/commonmarker/cmark/src/render.c +6 -5
  76. data/ext/commonmarker/cmark/src/scanners.c +1050 -1053
  77. data/ext/commonmarker/cmark/src/scanners.re +4 -4
  78. data/ext/commonmarker/cmark/test/pathological_tests.py +1 -1
  79. data/ext/commonmarker/cmark/test/spec.txt +179 -196
  80. data/lib/commonmarker/version.rb +1 -1
  81. data/test/test_attributes.rb +1 -1
  82. 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, int start_line,
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 & CMARK_NODE__OPEN); // shouldn't call finalize on closed blocks
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 = make_block(parser->mem, block_type, parser->line_number, start_column);
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, cmark_reference_map *refmap,
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, bufsize_t pos,
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 && (container->last_child->flags & CMARK_NODE__OPEN);
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
- parser->offset + 1);
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
- add_child(parser, *container, CMARK_NODE_HEADING, parser->offset + 1);
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
- parse_list_marker(parser->mem, input, parser->first_nonspace, &data)) &&
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, bufsize_t initial_size) {
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
- buf->asize ? buf->ptr : NULL, new_size);
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) {mem, cmark_strbuf__initbuf, 0, 0}
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, bufsize_t initial_size);
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, cmark_chunk *c) {
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, const char *str) {
78
- if (c->alloc) {
79
- mem->free(c->data);
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) abort();
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) abort();
22
+ if (!new_ptr)
23
+ abort();
22
24
  return new_ptr;
23
25
  }
24
26
 
25
- cmark_mem DEFAULT_MEM_ALLOCATOR = { xcalloc, xrealloc, free };
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
- void *(*calloc)(size_t, size_t);
99
- void *(*realloc)(void *, size_t);
100
- void (*free)(void *);
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, cmark_mem *mem);
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 && (c == '`' || c == '<' || c == '>' ||
45
- cmark_isspace(c) || c == '\\' || c == ')' ||
46
- c == '(')) ||
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
- node->parent->type == CMARK_NODE_ITEM;
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
- renderer->width == 0 &&
353
- !(CMARK_OPT_HARDBREAKS & options) &&
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, cmark_chunk s) {
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, cmark_chunk *content) {
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, int is_email) {
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, int is_email) {
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
- if (opener->delim_char == closer->delim_char && opener->can_open) {
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
- delimiter *opener;
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
- // look through list of delimiters for a [ or !
772
- opener = subj->last_delim;
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
- remove_delimiter(subj, opener);
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
- ref = cmark_reference_lookup(subj->refmap, &raw_label);
846
- cmark_chunk_free(subj->mem, &raw_label);
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
- remove_delimiter(subj, opener); // remove this opener from delimiter list
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->last_delim;
929
+ opener = subj->last_bracket;
886
930
  while (opener != NULL) {
887
- if (opener->delim_char == '[') {
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
- push_delimiter(subj, '[', true, false, new_inl);
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
- push_delimiter(subj, '!', false, true, new_inl);
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, cmark_reference_map *refmap,
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.