commonmarker 0.3.0 → 0.4.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/ext/commonmarker/cmark/CMakeLists.txt +10 -4
  3. data/ext/commonmarker/cmark/Makefile +5 -5
  4. data/ext/commonmarker/cmark/api_test/CMakeLists.txt +1 -1
  5. data/ext/commonmarker/cmark/api_test/main.c +16 -0
  6. data/ext/commonmarker/cmark/build/CMakeCache.txt +3 -4
  7. data/ext/commonmarker/cmark/build/CMakeFiles/2.8.10.1/CMakeSystem.cmake +4 -4
  8. data/ext/commonmarker/cmark/build/CMakeFiles/CMakeError.log +12 -12
  9. data/ext/commonmarker/cmark/build/CMakeFiles/CMakeOutput.log +97 -142
  10. data/ext/commonmarker/cmark/build/CMakeFiles/Makefile.cmake +0 -1
  11. data/ext/commonmarker/cmark/build/api_test/CMakeFiles/api_test.dir/build.make +1 -1
  12. data/ext/commonmarker/cmark/build/api_test/CMakeFiles/api_test.dir/link.txt +1 -1
  13. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/DependInfo.cmake +1 -1
  14. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/build.make +23 -23
  15. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/cmake_clean.cmake +2 -2
  16. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/link.txt +1 -1
  17. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/blocks.c.o +0 -0
  18. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/buffer.c.o +0 -0
  19. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/cmark.c.o +0 -0
  20. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/commonmark.c.o +0 -0
  21. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/houdini_html_u.c.o +0 -0
  22. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/html.c.o +0 -0
  23. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/inlines.c.o +0 -0
  24. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/node.c.o +0 -0
  25. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/references.c.o +0 -0
  26. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/render.c.o +0 -0
  27. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/scanners.c.o +0 -0
  28. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/utf8.c.o +0 -0
  29. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/xml.c.o +0 -0
  30. data/ext/commonmarker/cmark/build/src/cmake_install.cmake +3 -3
  31. data/ext/commonmarker/cmark/build/src/cmark_version.h +2 -2
  32. data/ext/commonmarker/cmark/build/src/config.h +6 -6
  33. data/ext/commonmarker/cmark/build/src/libcmark.a +0 -0
  34. data/ext/commonmarker/cmark/build/src/libcmark.pc +1 -1
  35. data/ext/commonmarker/cmark/build/testdir/CTestTestfile.cmake +4 -4
  36. data/ext/commonmarker/cmark/changelog.txt +46 -0
  37. data/ext/commonmarker/cmark/man/man3/cmark.3 +21 -20
  38. data/ext/commonmarker/cmark/src/CMakeLists.txt +4 -6
  39. data/ext/commonmarker/cmark/src/bench.h +8 -8
  40. data/ext/commonmarker/cmark/src/blocks.c +917 -947
  41. data/ext/commonmarker/cmark/src/buffer.c +213 -288
  42. data/ext/commonmarker/cmark/src/buffer.h +19 -21
  43. data/ext/commonmarker/cmark/src/chunk.h +78 -82
  44. data/ext/commonmarker/cmark/src/cmark.c +9 -17
  45. data/ext/commonmarker/cmark/src/cmark.h +113 -157
  46. data/ext/commonmarker/cmark/src/cmark_ctype.c +24 -35
  47. data/ext/commonmarker/cmark/src/commonmark.c +390 -425
  48. data/ext/commonmarker/cmark/src/config.h.in +6 -6
  49. data/ext/commonmarker/cmark/src/houdini.h +21 -15
  50. data/ext/commonmarker/cmark/src/houdini_href_e.c +50 -57
  51. data/ext/commonmarker/cmark/src/houdini_html_e.c +36 -51
  52. data/ext/commonmarker/cmark/src/houdini_html_u.c +119 -124
  53. data/ext/commonmarker/cmark/src/html.c +289 -307
  54. data/ext/commonmarker/cmark/src/inlines.c +976 -1030
  55. data/ext/commonmarker/cmark/src/inlines.h +4 -2
  56. data/ext/commonmarker/cmark/src/iterator.c +96 -126
  57. data/ext/commonmarker/cmark/src/iterator.h +5 -5
  58. data/ext/commonmarker/cmark/src/latex.c +379 -401
  59. data/ext/commonmarker/cmark/src/main.c +168 -175
  60. data/ext/commonmarker/cmark/src/man.c +212 -226
  61. data/ext/commonmarker/cmark/src/node.c +746 -839
  62. data/ext/commonmarker/cmark/src/node.h +47 -48
  63. data/ext/commonmarker/cmark/src/parser.h +14 -14
  64. data/ext/commonmarker/cmark/src/references.c +101 -111
  65. data/ext/commonmarker/cmark/src/references.h +10 -8
  66. data/ext/commonmarker/cmark/src/render.c +144 -167
  67. data/ext/commonmarker/cmark/src/render.h +22 -41
  68. data/ext/commonmarker/cmark/src/scanners.c +27695 -20903
  69. data/ext/commonmarker/cmark/src/scanners.h +2 -1
  70. data/ext/commonmarker/cmark/src/scanners.re +1 -1
  71. data/ext/commonmarker/cmark/src/utf8.c +276 -419
  72. data/ext/commonmarker/cmark/src/utf8.h +6 -6
  73. data/ext/commonmarker/cmark/src/xml.c +129 -144
  74. data/ext/commonmarker/cmark/test/CMakeLists.txt +4 -4
  75. data/ext/commonmarker/cmark/test/smart_punct.txt +8 -0
  76. data/ext/commonmarker/cmark/test/spec.txt +109 -47
  77. data/lib/commonmarker/version.rb +1 -1
  78. metadata +2 -2
@@ -19,1036 +19,1006 @@
19
19
 
20
20
  #define peek_at(i, n) (i)->data[n]
21
21
 
22
- static inline bool
23
- S_is_line_end_char(char c)
24
- {
25
- return (c == '\n' || c == '\r');
22
+ static inline bool S_is_line_end_char(char c) {
23
+ return (c == '\n' || c == '\r');
26
24
  }
27
25
 
28
- static void
29
- S_parser_feed(cmark_parser *parser, const unsigned char *buffer, size_t len,
30
- bool eof);
31
-
32
- static void
33
- S_process_line(cmark_parser *parser, const unsigned char *buffer,
34
- bufsize_t bytes);
35
-
36
- static cmark_node* make_block(cmark_node_type tag, int start_line, int start_column)
37
- {
38
- cmark_node* e;
39
-
40
- e = (cmark_node *)calloc(1, sizeof(*e));
41
- if(e != NULL) {
42
- e->type = tag;
43
- e->open = true;
44
- e->start_line = start_line;
45
- e->start_column = start_column;
46
- e->end_line = start_line;
47
- cmark_strbuf_init(&e->string_content, 32);
48
- }
49
-
50
- return e;
26
+ static void S_parser_feed(cmark_parser *parser, const unsigned char *buffer,
27
+ size_t len, bool eof);
28
+
29
+ static void S_process_line(cmark_parser *parser, const unsigned char *buffer,
30
+ bufsize_t bytes);
31
+
32
+ static cmark_node *make_block(cmark_node_type tag, int start_line,
33
+ int start_column) {
34
+ cmark_node *e;
35
+
36
+ e = (cmark_node *)calloc(1, sizeof(*e));
37
+ if (e != NULL) {
38
+ e->type = tag;
39
+ e->open = true;
40
+ e->start_line = start_line;
41
+ e->start_column = start_column;
42
+ e->end_line = start_line;
43
+ cmark_strbuf_init(&e->string_content, 32);
44
+ }
45
+
46
+ return e;
51
47
  }
52
48
 
53
49
  // Create a root document node.
54
- static cmark_node* make_document()
55
- {
56
- cmark_node *e = make_block(NODE_DOCUMENT, 1, 1);
57
- return e;
50
+ static cmark_node *make_document() {
51
+ cmark_node *e = make_block(NODE_DOCUMENT, 1, 1);
52
+ return e;
58
53
  }
59
54
 
60
- cmark_parser *cmark_parser_new(int options)
61
- {
62
- cmark_parser *parser = (cmark_parser*)malloc(sizeof(cmark_parser));
63
- cmark_node *document = make_document();
64
- cmark_strbuf *line = (cmark_strbuf*)malloc(sizeof(cmark_strbuf));
65
- cmark_strbuf *buf = (cmark_strbuf*)malloc(sizeof(cmark_strbuf));
66
- cmark_strbuf_init(line, 256);
67
- cmark_strbuf_init(buf, 0);
68
-
69
- parser->refmap = cmark_reference_map_new();
70
- parser->root = document;
71
- parser->current = document;
72
- parser->line_number = 0;
73
- parser->offset = 0;
74
- parser->column = 0;
75
- parser->first_nonspace = 0;
76
- parser->first_nonspace_column = 0;
77
- parser->indent = 0;
78
- parser->blank = false;
79
- parser->curline = line;
80
- parser->last_line_length = 0;
81
- parser->linebuf = buf;
82
- parser->options = options;
83
-
84
- return parser;
55
+ cmark_parser *cmark_parser_new(int options) {
56
+ cmark_parser *parser = (cmark_parser *)malloc(sizeof(cmark_parser));
57
+ cmark_node *document = make_document();
58
+ cmark_strbuf *line = (cmark_strbuf *)malloc(sizeof(cmark_strbuf));
59
+ cmark_strbuf *buf = (cmark_strbuf *)malloc(sizeof(cmark_strbuf));
60
+ cmark_strbuf_init(line, 256);
61
+ cmark_strbuf_init(buf, 0);
62
+
63
+ parser->refmap = cmark_reference_map_new();
64
+ parser->root = document;
65
+ parser->current = document;
66
+ parser->line_number = 0;
67
+ parser->offset = 0;
68
+ parser->column = 0;
69
+ parser->first_nonspace = 0;
70
+ parser->first_nonspace_column = 0;
71
+ parser->indent = 0;
72
+ parser->blank = false;
73
+ parser->curline = line;
74
+ parser->last_line_length = 0;
75
+ parser->linebuf = buf;
76
+ parser->options = options;
77
+
78
+ return parser;
85
79
  }
86
80
 
87
- void cmark_parser_free(cmark_parser *parser)
88
- {
89
- cmark_strbuf_free(parser->curline);
90
- free(parser->curline);
91
- cmark_strbuf_free(parser->linebuf);
92
- free(parser->linebuf);
93
- cmark_reference_map_free(parser->refmap);
94
- free(parser);
81
+ void cmark_parser_free(cmark_parser *parser) {
82
+ cmark_strbuf_free(parser->curline);
83
+ free(parser->curline);
84
+ cmark_strbuf_free(parser->linebuf);
85
+ free(parser->linebuf);
86
+ cmark_reference_map_free(parser->refmap);
87
+ free(parser);
95
88
  }
96
89
 
97
- static cmark_node*
98
- finalize(cmark_parser *parser, cmark_node* b);
90
+ static cmark_node *finalize(cmark_parser *parser, cmark_node *b);
99
91
 
100
92
  // Returns true if line has only space characters, else false.
101
- static bool is_blank(cmark_strbuf *s, bufsize_t offset)
102
- {
103
- while (offset < s->size) {
104
- switch (s->ptr[offset]) {
105
- case '\r':
106
- case '\n':
107
- return true;
108
- case ' ':
109
- offset++;
110
- break;
111
- case '\t':
112
- offset++;
113
- break;
114
- default:
115
- return false;
116
- }
117
- }
118
-
119
- return true;
93
+ static bool is_blank(cmark_strbuf *s, bufsize_t offset) {
94
+ while (offset < s->size) {
95
+ switch (s->ptr[offset]) {
96
+ case '\r':
97
+ case '\n':
98
+ return true;
99
+ case ' ':
100
+ offset++;
101
+ break;
102
+ case '\t':
103
+ offset++;
104
+ break;
105
+ default:
106
+ return false;
107
+ }
108
+ }
109
+
110
+ return true;
120
111
  }
121
112
 
122
- static inline bool can_contain(cmark_node_type parent_type, cmark_node_type child_type)
123
- {
124
- return ( parent_type == NODE_DOCUMENT ||
125
- parent_type == NODE_BLOCK_QUOTE ||
126
- parent_type == NODE_ITEM ||
127
- (parent_type == NODE_LIST && child_type == NODE_ITEM) );
113
+ static inline bool can_contain(cmark_node_type parent_type,
114
+ cmark_node_type child_type) {
115
+ return (parent_type == NODE_DOCUMENT || parent_type == NODE_BLOCK_QUOTE ||
116
+ parent_type == NODE_ITEM ||
117
+ (parent_type == NODE_LIST && child_type == NODE_ITEM));
128
118
  }
129
119
 
130
- static inline bool accepts_lines(cmark_node_type block_type)
131
- {
132
- return (block_type == NODE_PARAGRAPH ||
133
- block_type == NODE_HEADER ||
134
- block_type == NODE_CODE_BLOCK);
120
+ static inline bool accepts_lines(cmark_node_type block_type) {
121
+ return (block_type == NODE_PARAGRAPH || block_type == NODE_HEADER ||
122
+ block_type == NODE_CODE_BLOCK);
135
123
  }
136
124
 
137
- static void add_line(cmark_node* node, cmark_chunk *ch, bufsize_t offset)
138
- {
139
- assert(node->open);
140
- cmark_strbuf_put(&node->string_content, ch->data + offset, ch->len - offset);
125
+ static void add_line(cmark_node *node, cmark_chunk *ch, bufsize_t offset) {
126
+ assert(node->open);
127
+ cmark_strbuf_put(&node->string_content, ch->data + offset, ch->len - offset);
141
128
  }
142
129
 
143
- static void remove_trailing_blank_lines(cmark_strbuf *ln)
144
- {
145
- bufsize_t i;
146
- unsigned char c;
147
-
148
- for (i = ln->size - 1; i >= 0; --i) {
149
- c = ln->ptr[i];
130
+ static void remove_trailing_blank_lines(cmark_strbuf *ln) {
131
+ bufsize_t i;
132
+ unsigned char c;
150
133
 
151
- if (c != ' ' && c != '\t' && !S_is_line_end_char(c))
152
- break;
153
- }
134
+ for (i = ln->size - 1; i >= 0; --i) {
135
+ c = ln->ptr[i];
154
136
 
155
- if (i < 0) {
156
- cmark_strbuf_clear(ln);
157
- return;
158
- }
137
+ if (c != ' ' && c != '\t' && !S_is_line_end_char(c))
138
+ break;
139
+ }
159
140
 
141
+ if (i < 0) {
142
+ cmark_strbuf_clear(ln);
143
+ return;
144
+ }
160
145
 
161
- for(; i < ln->size; ++i) {
162
- c = ln->ptr[i];
146
+ for (; i < ln->size; ++i) {
147
+ c = ln->ptr[i];
163
148
 
164
- if (!S_is_line_end_char(c))
165
- continue;
149
+ if (!S_is_line_end_char(c))
150
+ continue;
166
151
 
167
- cmark_strbuf_truncate(ln, i);
168
- break;
169
- }
152
+ cmark_strbuf_truncate(ln, i);
153
+ break;
154
+ }
170
155
  }
171
156
 
172
157
  // Check to see if a node ends with a blank line, descending
173
158
  // if needed into lists and sublists.
174
- static bool ends_with_blank_line(cmark_node* node)
175
- {
176
- cmark_node *cur = node;
177
- while (cur != NULL) {
178
- if (cur->last_line_blank) {
179
- return true;
180
- }
181
- if (cur->type == NODE_LIST || cur->type == NODE_ITEM) {
182
- cur = cur->last_child;
183
- } else {
184
- cur = NULL;
185
- }
186
- }
187
- return false;
159
+ static bool ends_with_blank_line(cmark_node *node) {
160
+ cmark_node *cur = node;
161
+ while (cur != NULL) {
162
+ if (cur->last_line_blank) {
163
+ return true;
164
+ }
165
+ if (cur->type == NODE_LIST || cur->type == NODE_ITEM) {
166
+ cur = cur->last_child;
167
+ } else {
168
+ cur = NULL;
169
+ }
170
+ }
171
+ return false;
188
172
  }
189
173
 
190
174
  // Break out of all containing lists
191
- static int break_out_of_lists(cmark_parser *parser, cmark_node ** bptr)
192
- {
193
- cmark_node *container = *bptr;
194
- cmark_node *b = parser->root;
195
- // find first containing NODE_LIST:
196
- while (b && b->type != NODE_LIST) {
197
- b = b->last_child;
198
- }
199
- if (b) {
200
- while (container && container != b) {
201
- container = finalize(parser, container);
202
- }
203
- finalize(parser, b);
204
- *bptr = b->parent;
205
- }
206
- return 0;
175
+ static int break_out_of_lists(cmark_parser *parser, cmark_node **bptr) {
176
+ cmark_node *container = *bptr;
177
+ cmark_node *b = parser->root;
178
+ // find first containing NODE_LIST:
179
+ while (b && b->type != NODE_LIST) {
180
+ b = b->last_child;
181
+ }
182
+ if (b) {
183
+ while (container && container != b) {
184
+ container = finalize(parser, container);
185
+ }
186
+ finalize(parser, b);
187
+ *bptr = b->parent;
188
+ }
189
+ return 0;
207
190
  }
208
191
 
209
-
210
- static cmark_node*
211
- finalize(cmark_parser *parser, cmark_node* b)
212
- {
213
- bufsize_t pos;
214
- cmark_node* item;
215
- cmark_node* subitem;
216
- cmark_node* parent;
217
-
218
- parent = b->parent;
219
-
220
- assert(b->open); // shouldn't call finalize on closed blocks
221
- b->open = false;
222
-
223
- if (parser->curline->size == 0) {
224
- // end of input - line number has not been incremented
225
- b->end_line = parser->line_number;
226
- b->end_column = parser->last_line_length;
227
- } else if (b->type == NODE_DOCUMENT ||
228
- (b->type == NODE_CODE_BLOCK && b->as.code.fenced) ||
229
- (b->type == NODE_HEADER && b->as.header.setext)) {
230
- b->end_line = parser->line_number;
231
- b->end_column = parser->curline->size;
232
- if (b->end_column && parser->curline->ptr[b->end_column - 1] == '\n')
233
- b->end_column -= 1;
234
- if (b->end_column && parser->curline->ptr[b->end_column - 1] == '\r')
235
- b->end_column -= 1;
236
- } else {
237
- b->end_line = parser->line_number - 1;
238
- b->end_column = parser->last_line_length;
239
- }
240
-
241
- switch (b->type) {
242
- case NODE_PARAGRAPH:
243
- while (cmark_strbuf_at(&b->string_content, 0) == '[' &&
244
- (pos = cmark_parse_reference_inline(&b->string_content, parser->refmap))) {
245
-
246
- cmark_strbuf_drop(&b->string_content, pos);
247
- }
248
- if (is_blank(&b->string_content, 0)) {
249
- // remove blank node (former reference def)
250
- cmark_node_free(b);
251
- }
252
- break;
253
-
254
- case NODE_CODE_BLOCK:
255
- if (!b->as.code.fenced) { // indented code
256
- remove_trailing_blank_lines(&b->string_content);
257
- cmark_strbuf_putc(&b->string_content, '\n');
258
- } else {
259
-
260
- // first line of contents becomes info
261
- for (pos = 0; pos < b->string_content.size; ++pos) {
262
- if (S_is_line_end_char(b->string_content.ptr[pos]))
263
- break;
264
- }
265
- assert(pos < b->string_content.size);
266
-
267
- cmark_strbuf tmp = GH_BUF_INIT;
268
- houdini_unescape_html_f(
269
- &tmp,
270
- b->string_content.ptr,
271
- pos
272
- );
273
- cmark_strbuf_trim(&tmp);
274
- cmark_strbuf_unescape(&tmp);
275
- b->as.code.info = cmark_chunk_buf_detach(&tmp);
276
-
277
- if (b->string_content.ptr[pos] == '\r')
278
- pos += 1;
279
- if (b->string_content.ptr[pos] == '\n')
280
- pos += 1;
281
- cmark_strbuf_drop(&b->string_content, pos);
282
- }
283
- b->as.code.literal = cmark_chunk_buf_detach(&b->string_content);
284
- break;
285
-
286
- case NODE_HTML:
287
- b->as.literal = cmark_chunk_buf_detach(&b->string_content);
288
- break;
289
-
290
- case NODE_LIST: // determine tight/loose status
291
- b->as.list.tight = true; // tight by default
292
- item = b->first_child;
293
-
294
- while (item) {
295
- // check for non-final non-empty list item ending with blank line:
296
- if (item->last_line_blank && item->next) {
297
- b->as.list.tight = false;
298
- break;
299
- }
300
- // recurse into children of list item, to see if there are
301
- // spaces between them:
302
- subitem = item->first_child;
303
- while (subitem) {
304
- if (ends_with_blank_line(subitem) &&
305
- (item->next || subitem->next)) {
306
- b->as.list.tight = false;
307
- break;
308
- }
309
- subitem = subitem->next;
310
- }
311
- if (!(b->as.list.tight)) {
312
- break;
313
- }
314
- item = item->next;
315
- }
316
-
317
- break;
318
-
319
- default:
320
- break;
321
- }
322
- return parent;
192
+ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
193
+ bufsize_t pos;
194
+ cmark_node *item;
195
+ cmark_node *subitem;
196
+ cmark_node *parent;
197
+
198
+ parent = b->parent;
199
+
200
+ assert(b->open); // shouldn't call finalize on closed blocks
201
+ b->open = false;
202
+
203
+ if (parser->curline->size == 0) {
204
+ // end of input - line number has not been incremented
205
+ b->end_line = parser->line_number;
206
+ b->end_column = parser->last_line_length;
207
+ } else if (b->type == NODE_DOCUMENT ||
208
+ (b->type == NODE_CODE_BLOCK && b->as.code.fenced) ||
209
+ (b->type == NODE_HEADER && b->as.header.setext)) {
210
+ b->end_line = parser->line_number;
211
+ b->end_column = parser->curline->size;
212
+ if (b->end_column && parser->curline->ptr[b->end_column - 1] == '\n')
213
+ b->end_column -= 1;
214
+ if (b->end_column && parser->curline->ptr[b->end_column - 1] == '\r')
215
+ b->end_column -= 1;
216
+ } else {
217
+ b->end_line = parser->line_number - 1;
218
+ b->end_column = parser->last_line_length;
219
+ }
220
+
221
+ switch (b->type) {
222
+ case NODE_PARAGRAPH:
223
+ while (cmark_strbuf_at(&b->string_content, 0) == '[' &&
224
+ (pos = cmark_parse_reference_inline(&b->string_content,
225
+ parser->refmap))) {
226
+
227
+ cmark_strbuf_drop(&b->string_content, pos);
228
+ }
229
+ if (is_blank(&b->string_content, 0)) {
230
+ // remove blank node (former reference def)
231
+ cmark_node_free(b);
232
+ }
233
+ break;
234
+
235
+ case NODE_CODE_BLOCK:
236
+ if (!b->as.code.fenced) { // indented code
237
+ remove_trailing_blank_lines(&b->string_content);
238
+ cmark_strbuf_putc(&b->string_content, '\n');
239
+ } else {
240
+
241
+ // first line of contents becomes info
242
+ for (pos = 0; pos < b->string_content.size; ++pos) {
243
+ if (S_is_line_end_char(b->string_content.ptr[pos]))
244
+ break;
245
+ }
246
+ assert(pos < b->string_content.size);
247
+
248
+ cmark_strbuf tmp = GH_BUF_INIT;
249
+ houdini_unescape_html_f(&tmp, b->string_content.ptr, pos);
250
+ cmark_strbuf_trim(&tmp);
251
+ cmark_strbuf_unescape(&tmp);
252
+ b->as.code.info = cmark_chunk_buf_detach(&tmp);
253
+
254
+ if (b->string_content.ptr[pos] == '\r')
255
+ pos += 1;
256
+ if (b->string_content.ptr[pos] == '\n')
257
+ pos += 1;
258
+ cmark_strbuf_drop(&b->string_content, pos);
259
+ }
260
+ b->as.code.literal = cmark_chunk_buf_detach(&b->string_content);
261
+ break;
262
+
263
+ case NODE_HTML:
264
+ b->as.literal = cmark_chunk_buf_detach(&b->string_content);
265
+ break;
266
+
267
+ case NODE_LIST: // determine tight/loose status
268
+ b->as.list.tight = true; // tight by default
269
+ item = b->first_child;
270
+
271
+ while (item) {
272
+ // check for non-final non-empty list item ending with blank line:
273
+ if (item->last_line_blank && item->next) {
274
+ b->as.list.tight = false;
275
+ break;
276
+ }
277
+ // recurse into children of list item, to see if there are
278
+ // spaces between them:
279
+ subitem = item->first_child;
280
+ while (subitem) {
281
+ if (ends_with_blank_line(subitem) && (item->next || subitem->next)) {
282
+ b->as.list.tight = false;
283
+ break;
284
+ }
285
+ subitem = subitem->next;
286
+ }
287
+ if (!(b->as.list.tight)) {
288
+ break;
289
+ }
290
+ item = item->next;
291
+ }
292
+
293
+ break;
294
+
295
+ default:
296
+ break;
297
+ }
298
+ return parent;
323
299
  }
324
300
 
325
301
  // Add a node as child of another. Return pointer to child.
326
- static cmark_node* add_child(cmark_parser *parser, cmark_node* parent,
327
- cmark_node_type block_type, int start_column)
328
- {
329
- assert(parent);
330
-
331
- // if 'parent' isn't the kind of node that can accept this child,
332
- // then back up til we hit a node that can.
333
- while (!can_contain(parent->type, block_type)) {
334
- parent = finalize(parser, parent);
335
- }
336
-
337
- cmark_node* child = make_block(block_type, parser->line_number, start_column);
338
- child->parent = parent;
339
-
340
- if (parent->last_child) {
341
- parent->last_child->next = child;
342
- child->prev = parent->last_child;
343
- } else {
344
- parent->first_child = child;
345
- child->prev = NULL;
346
- }
347
- parent->last_child = child;
348
- return child;
302
+ static cmark_node *add_child(cmark_parser *parser, cmark_node *parent,
303
+ cmark_node_type block_type, int start_column) {
304
+ assert(parent);
305
+
306
+ // if 'parent' isn't the kind of node that can accept this child,
307
+ // then back up til we hit a node that can.
308
+ while (!can_contain(parent->type, block_type)) {
309
+ parent = finalize(parser, parent);
310
+ }
311
+
312
+ cmark_node *child = make_block(block_type, parser->line_number, start_column);
313
+ child->parent = parent;
314
+
315
+ if (parent->last_child) {
316
+ parent->last_child->next = child;
317
+ child->prev = parent->last_child;
318
+ } else {
319
+ parent->first_child = child;
320
+ child->prev = NULL;
321
+ }
322
+ parent->last_child = child;
323
+ return child;
349
324
  }
350
325
 
351
-
352
326
  // Walk through node and all children, recursively, parsing
353
327
  // string content into inline content where appropriate.
354
- static void process_inlines(cmark_node* root, cmark_reference_map *refmap, int options)
355
- {
356
- cmark_iter *iter = cmark_iter_new(root);
357
- cmark_node *cur;
358
- cmark_event_type ev_type;
359
-
360
- while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
361
- cur = cmark_iter_get_node(iter);
362
- if (ev_type == CMARK_EVENT_ENTER) {
363
- if (cur->type == NODE_PARAGRAPH ||
364
- cur->type == NODE_HEADER) {
365
- cmark_parse_inlines(cur, refmap, options);
366
- }
367
- }
368
- }
369
-
370
- cmark_iter_free(iter);
328
+ static void process_inlines(cmark_node *root, cmark_reference_map *refmap,
329
+ int options) {
330
+ cmark_iter *iter = cmark_iter_new(root);
331
+ cmark_node *cur;
332
+ cmark_event_type ev_type;
333
+
334
+ while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
335
+ cur = cmark_iter_get_node(iter);
336
+ if (ev_type == CMARK_EVENT_ENTER) {
337
+ if (cur->type == NODE_PARAGRAPH || cur->type == NODE_HEADER) {
338
+ cmark_parse_inlines(cur, refmap, options);
339
+ }
340
+ }
341
+ }
342
+
343
+ cmark_iter_free(iter);
371
344
  }
372
345
 
373
346
  // Attempts to parse a list item marker (bullet or enumerated).
374
347
  // On success, returns length of the marker, and populates
375
348
  // data with the details. On failure, returns 0.
376
- static bufsize_t parse_list_marker(cmark_chunk *input, bufsize_t pos, cmark_list **dataptr)
377
- {
378
- unsigned char c;
379
- bufsize_t startpos;
380
- cmark_list *data;
381
-
382
- startpos = pos;
383
- c = peek_at(input, pos);
384
-
385
- if (c == '*' || c == '-' || c == '+') {
386
- pos++;
387
- if (!cmark_isspace(peek_at(input, pos))) {
388
- return 0;
389
- }
390
- data = (cmark_list *)calloc(1, sizeof(*data));
391
- if(data == NULL) {
392
- return 0;
393
- } else {
394
- data->marker_offset = 0; // will be adjusted later
395
- data->list_type = CMARK_BULLET_LIST;
396
- data->bullet_char = c;
397
- data->start = 1;
398
- data->delimiter = CMARK_PERIOD_DELIM;
399
- data->tight = false;
400
- }
401
- } else if (cmark_isdigit(c)) {
402
- int start = 0;
403
- int digits = 0;
404
-
405
- do {
406
- start = (10 * start) + (peek_at(input, pos) - '0');
407
- pos++;
408
- digits++;
409
- // We limit to 9 digits to avoid overflow,
410
- // assuming max int is 2^31 - 1
411
- // This also seems to be the limit for 'start' in some browsers.
412
- } while (digits < 9 && cmark_isdigit(peek_at(input, pos)));
413
-
414
- c = peek_at(input, pos);
415
- if (c == '.' || c == ')') {
416
- pos++;
417
- if (!cmark_isspace(peek_at(input, pos))) {
418
- return 0;
419
- }
420
- data = (cmark_list *)calloc(1, sizeof(*data));
421
- if(data == NULL) {
422
- return 0;
423
- } else {
424
- data->marker_offset = 0; // will be adjusted later
425
- data->list_type = CMARK_ORDERED_LIST;
426
- data->bullet_char = 0;
427
- data->start = start;
428
- data->delimiter = (c == '.' ? CMARK_PERIOD_DELIM : CMARK_PAREN_DELIM);
429
- data->tight = false;
430
- }
431
- } else {
432
- return 0;
433
- }
434
-
435
- } else {
436
- return 0;
437
- }
438
-
439
- *dataptr = data;
440
- return (pos - startpos);
349
+ static bufsize_t parse_list_marker(cmark_chunk *input, bufsize_t pos,
350
+ cmark_list **dataptr) {
351
+ unsigned char c;
352
+ bufsize_t startpos;
353
+ cmark_list *data;
354
+
355
+ startpos = pos;
356
+ c = peek_at(input, pos);
357
+
358
+ if (c == '*' || c == '-' || c == '+') {
359
+ pos++;
360
+ if (!cmark_isspace(peek_at(input, pos))) {
361
+ return 0;
362
+ }
363
+ data = (cmark_list *)calloc(1, sizeof(*data));
364
+ if (data == NULL) {
365
+ return 0;
366
+ } else {
367
+ data->marker_offset = 0; // will be adjusted later
368
+ data->list_type = CMARK_BULLET_LIST;
369
+ data->bullet_char = c;
370
+ data->start = 1;
371
+ data->delimiter = CMARK_PERIOD_DELIM;
372
+ data->tight = false;
373
+ }
374
+ } else if (cmark_isdigit(c)) {
375
+ int start = 0;
376
+ int digits = 0;
377
+
378
+ do {
379
+ start = (10 * start) + (peek_at(input, pos) - '0');
380
+ pos++;
381
+ digits++;
382
+ // We limit to 9 digits to avoid overflow,
383
+ // assuming max int is 2^31 - 1
384
+ // This also seems to be the limit for 'start' in some browsers.
385
+ } while (digits < 9 && cmark_isdigit(peek_at(input, pos)));
386
+
387
+ c = peek_at(input, pos);
388
+ if (c == '.' || c == ')') {
389
+ pos++;
390
+ if (!cmark_isspace(peek_at(input, pos))) {
391
+ return 0;
392
+ }
393
+ data = (cmark_list *)calloc(1, sizeof(*data));
394
+ if (data == NULL) {
395
+ return 0;
396
+ } else {
397
+ data->marker_offset = 0; // will be adjusted later
398
+ data->list_type = CMARK_ORDERED_LIST;
399
+ data->bullet_char = 0;
400
+ data->start = start;
401
+ data->delimiter = (c == '.' ? CMARK_PERIOD_DELIM : CMARK_PAREN_DELIM);
402
+ data->tight = false;
403
+ }
404
+ } else {
405
+ return 0;
406
+ }
407
+
408
+ } else {
409
+ return 0;
410
+ }
411
+
412
+ *dataptr = data;
413
+ return (pos - startpos);
441
414
  }
442
415
 
443
416
  // Return 1 if list item belongs in list, else 0.
444
- static int lists_match(cmark_list *list_data, cmark_list *item_data)
445
- {
446
- return (list_data->list_type == item_data->list_type &&
447
- list_data->delimiter == item_data->delimiter &&
448
- // list_data->marker_offset == item_data.marker_offset &&
449
- list_data->bullet_char == item_data->bullet_char);
417
+ static int lists_match(cmark_list *list_data, cmark_list *item_data) {
418
+ return (list_data->list_type == item_data->list_type &&
419
+ list_data->delimiter == item_data->delimiter &&
420
+ // list_data->marker_offset == item_data.marker_offset &&
421
+ list_data->bullet_char == item_data->bullet_char);
450
422
  }
451
423
 
452
- static cmark_node *finalize_document(cmark_parser *parser)
453
- {
454
- while (parser->current != parser->root) {
455
- parser->current = finalize(parser, parser->current);
456
- }
424
+ static cmark_node *finalize_document(cmark_parser *parser) {
425
+ while (parser->current != parser->root) {
426
+ parser->current = finalize(parser, parser->current);
427
+ }
457
428
 
458
- finalize(parser, parser->root);
459
- process_inlines(parser->root, parser->refmap, parser->options);
429
+ finalize(parser, parser->root);
430
+ process_inlines(parser->root, parser->refmap, parser->options);
460
431
 
461
- return parser->root;
432
+ return parser->root;
462
433
  }
463
434
 
464
- cmark_node *cmark_parse_file(FILE *f, int options)
465
- {
466
- unsigned char buffer[4096];
467
- cmark_parser *parser = cmark_parser_new(options);
468
- size_t bytes;
469
- cmark_node *document;
470
-
471
- while ((bytes = fread(buffer, 1, sizeof(buffer), f)) > 0) {
472
- bool eof = bytes < sizeof(buffer);
473
- S_parser_feed(parser, buffer, bytes, eof);
474
- if (eof) {
475
- break;
476
- }
477
- }
478
-
479
- document = cmark_parser_finish(parser);
480
- cmark_parser_free(parser);
481
- return document;
435
+ cmark_node *cmark_parse_file(FILE *f, int options) {
436
+ unsigned char buffer[4096];
437
+ cmark_parser *parser = cmark_parser_new(options);
438
+ size_t bytes;
439
+ cmark_node *document;
440
+
441
+ while ((bytes = fread(buffer, 1, sizeof(buffer), f)) > 0) {
442
+ bool eof = bytes < sizeof(buffer);
443
+ S_parser_feed(parser, buffer, bytes, eof);
444
+ if (eof) {
445
+ break;
446
+ }
447
+ }
448
+
449
+ document = cmark_parser_finish(parser);
450
+ cmark_parser_free(parser);
451
+ return document;
482
452
  }
483
453
 
484
- cmark_node *cmark_parse_document(const char *buffer, size_t len, int options)
485
- {
486
- cmark_parser *parser = cmark_parser_new(options);
487
- cmark_node *document;
454
+ cmark_node *cmark_parse_document(const char *buffer, size_t len, int options) {
455
+ cmark_parser *parser = cmark_parser_new(options);
456
+ cmark_node *document;
488
457
 
489
- S_parser_feed(parser, (const unsigned char *)buffer, len, true);
458
+ S_parser_feed(parser, (const unsigned char *)buffer, len, true);
490
459
 
491
- document = cmark_parser_finish(parser);
492
- cmark_parser_free(parser);
493
- return document;
460
+ document = cmark_parser_finish(parser);
461
+ cmark_parser_free(parser);
462
+ return document;
494
463
  }
495
464
 
496
- void
497
- cmark_parser_feed(cmark_parser *parser, const char *buffer, size_t len)
498
- {
499
- S_parser_feed(parser, (const unsigned char *)buffer, len, false);
465
+ void cmark_parser_feed(cmark_parser *parser, const char *buffer, size_t len) {
466
+ S_parser_feed(parser, (const unsigned char *)buffer, len, false);
500
467
  }
501
468
 
502
- static void
503
- S_parser_feed(cmark_parser *parser, const unsigned char *buffer, size_t len,
504
- bool eof)
505
- {
506
- const unsigned char *end = buffer + len;
507
- static const uint8_t repl[] = {239, 191, 189};
508
-
509
- while (buffer < end) {
510
- const unsigned char *eol;
511
- bufsize_t chunk_len;
512
- bool process = false;
513
- for (eol = buffer; eol < end; ++eol) {
514
- if (S_is_line_end_char(*eol)) {
515
- if (eol < end && *eol == '\r')
516
- eol++;
517
- if (eol < end && *eol == '\n')
518
- eol++;
519
- process = true;
520
- break;
521
- }
522
- if (*eol == '\0' && eol < end) {
523
- break;
524
- }
525
- }
526
- if (eol >= end && eof) {
527
- process = true;
528
- }
529
-
530
- chunk_len = cmark_strbuf_check_bufsize(eol - buffer);
531
- if (process) {
532
- if (parser->linebuf->size > 0) {
533
- cmark_strbuf_put(parser->linebuf, buffer, chunk_len);
534
- S_process_line(parser, parser->linebuf->ptr,
535
- parser->linebuf->size);
536
- cmark_strbuf_clear(parser->linebuf);
537
- } else {
538
- S_process_line(parser, buffer, chunk_len);
539
- }
540
- } else {
541
- if (eol < end && *eol == '\0') {
542
- // omit NULL byte
543
- cmark_strbuf_put(parser->linebuf, buffer, chunk_len);
544
- // add replacement character
545
- cmark_strbuf_put(parser->linebuf, repl, 3);
546
- chunk_len += 1; // so we advance the buffer past NULL
547
- } else {
548
- cmark_strbuf_put(parser->linebuf, buffer, chunk_len);
549
- }
550
- }
551
-
552
- buffer += chunk_len;
553
- }
469
+ static void S_parser_feed(cmark_parser *parser, const unsigned char *buffer,
470
+ size_t len, bool eof) {
471
+ const unsigned char *end = buffer + len;
472
+ static const uint8_t repl[] = {239, 191, 189};
473
+
474
+ while (buffer < end) {
475
+ const unsigned char *eol;
476
+ bufsize_t chunk_len;
477
+ bool process = false;
478
+ for (eol = buffer; eol < end; ++eol) {
479
+ if (S_is_line_end_char(*eol)) {
480
+ process = true;
481
+ break;
482
+ }
483
+ if (*eol == '\0' && eol < end) {
484
+ break;
485
+ }
486
+ }
487
+ if (eol >= end && eof) {
488
+ process = true;
489
+ }
490
+
491
+ chunk_len = cmark_strbuf_check_bufsize(eol - buffer);
492
+ if (process) {
493
+ if (parser->linebuf->size > 0) {
494
+ cmark_strbuf_put(parser->linebuf, buffer, chunk_len);
495
+ S_process_line(parser, parser->linebuf->ptr, parser->linebuf->size);
496
+ cmark_strbuf_clear(parser->linebuf);
497
+ } else {
498
+ S_process_line(parser, buffer, chunk_len);
499
+ }
500
+ } else {
501
+ if (eol < end && *eol == '\0') {
502
+ // omit NULL byte
503
+ cmark_strbuf_put(parser->linebuf, buffer, chunk_len);
504
+ // add replacement character
505
+ cmark_strbuf_put(parser->linebuf, repl, 3);
506
+ chunk_len += 1; // so we advance the buffer past NULL
507
+ } else {
508
+ cmark_strbuf_put(parser->linebuf, buffer, chunk_len);
509
+ }
510
+ }
511
+
512
+ buffer += chunk_len;
513
+ // skip over line ending characters:
514
+ if (buffer < end && *buffer == '\r')
515
+ buffer++;
516
+ if (buffer < end && *buffer == '\n')
517
+ buffer++;
518
+ }
554
519
  }
555
520
 
556
- static void chop_trailing_hashtags(cmark_chunk *ch)
557
- {
558
- bufsize_t n, orig_n;
521
+ static void chop_trailing_hashtags(cmark_chunk *ch) {
522
+ bufsize_t n, orig_n;
559
523
 
560
- cmark_chunk_rtrim(ch);
561
- orig_n = n = ch->len - 1;
524
+ cmark_chunk_rtrim(ch);
525
+ orig_n = n = ch->len - 1;
562
526
 
563
- // if string ends in space followed by #s, remove these:
564
- while (n >= 0 && peek_at(ch, n) == '#')
565
- n--;
527
+ // if string ends in space followed by #s, remove these:
528
+ while (n >= 0 && peek_at(ch, n) == '#')
529
+ n--;
566
530
 
567
- // Check for a space before the final #s:
568
- if (n != orig_n && n >= 0 &&
569
- (peek_at(ch, n) == ' ' || peek_at(ch, n) == '\t')) {
570
- ch->len = n;
571
- cmark_chunk_rtrim(ch);
572
- }
531
+ // Check for a space before the final #s:
532
+ if (n != orig_n && n >= 0 &&
533
+ (peek_at(ch, n) == ' ' || peek_at(ch, n) == '\t')) {
534
+ ch->len = n;
535
+ cmark_chunk_rtrim(ch);
536
+ }
573
537
  }
574
538
 
575
- static void
576
- S_find_first_nonspace(cmark_parser *parser, cmark_chunk *input)
577
- {
578
- char c;
579
- int chars_to_tab = TAB_STOP - (parser->column % TAB_STOP);
580
-
581
- parser->first_nonspace = parser->offset;
582
- parser->first_nonspace_column = parser->column;
583
- while ((c = peek_at(input, parser->first_nonspace))) {
584
- if (c == ' ') {
585
- parser->first_nonspace += 1;
586
- parser->first_nonspace_column += 1;
587
- chars_to_tab = chars_to_tab - 1;
588
- if (chars_to_tab == 0) {
589
- chars_to_tab = TAB_STOP;
590
- }
591
- } else if (c == '\t') {
592
- parser->first_nonspace += 1;
593
- parser->first_nonspace_column += chars_to_tab;
594
- chars_to_tab = TAB_STOP;
595
- } else {
596
- break;
597
- }
598
- }
599
-
600
- parser->indent = parser->first_nonspace_column - parser->column;
601
- parser->blank = S_is_line_end_char(peek_at(input, parser->first_nonspace));
539
+ static void S_find_first_nonspace(cmark_parser *parser, cmark_chunk *input) {
540
+ char c;
541
+ int chars_to_tab = TAB_STOP - (parser->column % TAB_STOP);
542
+
543
+ parser->first_nonspace = parser->offset;
544
+ parser->first_nonspace_column = parser->column;
545
+ while ((c = peek_at(input, parser->first_nonspace))) {
546
+ if (c == ' ') {
547
+ parser->first_nonspace += 1;
548
+ parser->first_nonspace_column += 1;
549
+ chars_to_tab = chars_to_tab - 1;
550
+ if (chars_to_tab == 0) {
551
+ chars_to_tab = TAB_STOP;
552
+ }
553
+ } else if (c == '\t') {
554
+ parser->first_nonspace += 1;
555
+ parser->first_nonspace_column += chars_to_tab;
556
+ chars_to_tab = TAB_STOP;
557
+ } else {
558
+ break;
559
+ }
560
+ }
561
+
562
+ parser->indent = parser->first_nonspace_column - parser->column;
563
+ parser->blank = S_is_line_end_char(peek_at(input, parser->first_nonspace));
602
564
  }
603
565
 
604
- static void
605
- S_advance_offset(cmark_parser *parser, cmark_chunk *input, bufsize_t count, bool columns)
606
- {
607
- char c;
608
- int chars_to_tab;
609
- while (count > 0 && (c = peek_at(input, parser->offset))) {
610
- if (c == '\t') {
611
- chars_to_tab = 4 - (parser->column % TAB_STOP);
612
- parser->column += chars_to_tab;
613
- parser->offset += 1;
614
- count -= (columns ? chars_to_tab : 1);
615
- } else {
616
- parser->offset += 1;
617
- parser->column += 1; // assume ascii; block starts are ascii
618
- count -= 1;
619
- }
620
- }
566
+ static void S_advance_offset(cmark_parser *parser, cmark_chunk *input,
567
+ bufsize_t count, bool columns) {
568
+ char c;
569
+ int chars_to_tab;
570
+ while (count > 0 && (c = peek_at(input, parser->offset))) {
571
+ if (c == '\t') {
572
+ chars_to_tab = 4 - (parser->column % TAB_STOP);
573
+ parser->column += chars_to_tab;
574
+ parser->offset += 1;
575
+ count -= (columns ? chars_to_tab : 1);
576
+ } else {
577
+ parser->offset += 1;
578
+ parser->column += 1; // assume ascii; block starts are ascii
579
+ count -= 1;
580
+ }
581
+ }
621
582
  }
622
583
 
623
-
624
- static void
625
- S_process_line(cmark_parser *parser, const unsigned char *buffer, bufsize_t bytes)
626
- {
627
- cmark_node* last_matched_container;
628
- bufsize_t matched = 0;
629
- int lev = 0;
630
- int i;
631
- cmark_list *data = NULL;
632
- bool all_matched = true;
633
- cmark_node* container;
634
- bool indented;
635
- cmark_chunk input;
636
- bool maybe_lazy;
637
-
638
- if (parser->options & CMARK_OPT_VALIDATE_UTF8) {
639
- utf8proc_check(parser->curline, buffer, bytes);
640
- } else {
641
- cmark_strbuf_put(parser->curline, buffer, bytes);
642
- }
643
- parser->offset = 0;
644
- parser->column = 0;
645
- parser->blank = false;
646
-
647
- input.data = parser->curline->ptr;
648
- input.len = parser->curline->size;
649
-
650
- // container starts at the document root.
651
- container = parser->root;
652
-
653
- parser->line_number++;
654
-
655
- // for each containing node, try to parse the associated line start.
656
- // bail out on failure: container will point to the last matching node.
657
-
658
- while (container->last_child && container->last_child->open) {
659
- container = container->last_child;
660
-
661
- S_find_first_nonspace(parser, &input);
662
-
663
- if (container->type == NODE_BLOCK_QUOTE) {
664
- matched = parser->indent <= 3 && peek_at(&input, parser->first_nonspace) == '>';
665
- if (matched) {
666
- S_advance_offset(parser, &input, parser->indent + 1, true);
667
- if (peek_at(&input, parser->offset) == ' ')
668
- parser->offset++;
669
- } else {
670
- all_matched = false;
671
- }
672
-
673
- } else if (container->type == NODE_ITEM) {
674
- if (parser->indent >= container->as.list.marker_offset +
675
- container->as.list.padding) {
676
- S_advance_offset(parser, &input,
677
- container->as.list.marker_offset +
678
- container->as.list.padding, true);
679
- } else if (parser->blank) {
680
- S_advance_offset(parser, &input,
681
- parser->first_nonspace - parser->offset, false);
682
- } else {
683
- all_matched = false;
684
- }
685
-
686
- } else if (container->type == NODE_CODE_BLOCK) {
687
-
688
- if (!container->as.code.fenced) { // indented
689
- if (parser->indent >= CODE_INDENT) {
690
- S_advance_offset(parser, &input, CODE_INDENT, true);
691
- } else if (parser->blank) {
692
- S_advance_offset(parser, &input,
693
- parser->first_nonspace - parser->offset,
694
- false);
695
- } else {
696
- all_matched = false;
697
- }
698
- } else { // fenced
699
- matched = 0;
700
- if (parser->indent <= 3 &&
701
- (peek_at(&input, parser->first_nonspace) ==
702
- container->as.code.fence_char)) {
703
- matched = scan_close_code_fence(&input,
704
- parser->first_nonspace);
705
- }
706
- if (matched >= container->as.code.fence_length) {
707
- // closing fence - and since we're at
708
- // the end of a line, we can return:
709
- all_matched = false;
710
- S_advance_offset(parser, &input, matched, false);
711
- parser->current = finalize(parser, container);
712
- goto finished;
713
- } else {
714
- // skip opt. spaces of fence parser->offset
715
- i = container->as.code.fence_offset;
716
- while (i > 0 &&
717
- peek_at(&input, parser->offset) == ' ') {
718
- S_advance_offset(parser, &input, 1, false);
719
- i--;
720
- }
721
- }
722
- }
723
- } else if (container->type == NODE_HEADER) {
724
-
725
- // a header can never contain more than one line
726
- all_matched = false;
727
-
728
- } else if (container->type == NODE_HTML) {
729
-
730
- switch (container->as.html_block_type) {
731
- case 1:
732
- case 2:
733
- case 3:
734
- case 4:
735
- case 5:
736
- // these types of blocks can accept blanks
737
- break;
738
- case 6:
739
- case 7:
740
- if (parser->blank) {
741
- all_matched = false;
742
- }
743
- break;
744
- default:
745
- fprintf(stderr,
746
- "Error (%s:%d): Unknown HTML block type %d\n",
747
- __FILE__, __LINE__,
748
- container->as.html_block_type);
749
- exit(1);
750
- }
751
-
752
- } else if (container->type == NODE_PARAGRAPH) {
753
-
754
- if (parser->blank) {
755
- all_matched = false;
756
- }
757
-
758
- }
759
-
760
- if (!all_matched) {
761
- container = container->parent; // back up to last matching node
762
- break;
763
- }
764
- }
765
-
766
- last_matched_container = container;
767
-
768
- // check to see if we've hit 2nd blank line, break out of list:
769
- if (parser->blank && container->last_line_blank) {
770
- break_out_of_lists(parser, &container);
771
- }
772
-
773
- maybe_lazy = parser->current->type == NODE_PARAGRAPH;
774
- // try new container starts:
775
- while (container->type != NODE_CODE_BLOCK &&
776
- container->type != NODE_HTML) {
777
-
778
- S_find_first_nonspace(parser, &input);
779
- indented = parser->indent >= CODE_INDENT;
780
-
781
- if (!indented && peek_at(&input, parser->first_nonspace) == '>') {
782
-
783
- S_advance_offset(parser, &input, parser->first_nonspace + 1 - parser->offset, false);
784
- // optional following character
785
- if (peek_at(&input, parser->offset) == ' ')
786
- S_advance_offset(parser, &input, 1, false);
787
- container = add_child(parser, container, NODE_BLOCK_QUOTE, parser->offset + 1);
788
-
789
- } else if (!indented && (matched = scan_atx_header_start(&input, parser->first_nonspace))) {
790
-
791
- S_advance_offset(parser, &input,
792
- parser->first_nonspace + matched - parser->offset, false);
793
- container = add_child(parser, container, NODE_HEADER, parser->offset + 1);
794
-
795
- bufsize_t hashpos = cmark_chunk_strchr(&input, '#', parser->first_nonspace);
796
- int level = 0;
797
-
798
- while (peek_at(&input, hashpos) == '#') {
799
- level++;
800
- hashpos++;
801
- }
802
- container->as.header.level = level;
803
- container->as.header.setext = false;
804
-
805
- } else if (!indented && (matched = scan_open_code_fence(&input, parser->first_nonspace))) {
806
-
807
- container = add_child(parser, container, NODE_CODE_BLOCK, parser->first_nonspace + 1);
808
- container->as.code.fenced = true;
809
- container->as.code.fence_char = peek_at(&input, parser->first_nonspace);
810
- container->as.code.fence_length = matched;
811
- container->as.code.fence_offset = parser->first_nonspace - parser->offset;
812
- container->as.code.info = cmark_chunk_literal("");
813
- S_advance_offset(parser, &input, parser->first_nonspace + matched - parser->offset, false);
814
-
815
- } else if (!indented &&
816
- ((matched = scan_html_block_start(&input, parser->first_nonspace)) ||
817
- (container->type != NODE_PARAGRAPH &&
818
- (matched = scan_html_block_start_7(&input, parser->first_nonspace))))) {
819
-
820
- container = add_child(parser, container, NODE_HTML, parser->first_nonspace + 1);
821
- container->as.html_block_type = matched;
822
- // note, we don't adjust parser->offset because the tag is part of the text
823
-
824
- } else if (!indented &&
825
- container->type == NODE_PARAGRAPH &&
826
- (lev = scan_setext_header_line(&input, parser->first_nonspace)) &&
827
- // check that there is only one line in the paragraph:
828
- (cmark_strbuf_strrchr(&container->string_content, '\n',
829
- cmark_strbuf_len(&container->string_content) - 2) < 0)) {
830
-
831
- container->type = NODE_HEADER;
832
- container->as.header.level = lev;
833
- container->as.header.setext = true;
834
- S_advance_offset(parser, &input, input.len - 1 - parser->offset, false);
835
-
836
- } else if (!indented &&
837
- !(container->type == NODE_PARAGRAPH &&
838
- !all_matched) &&
839
- (matched = scan_hrule(&input, parser->first_nonspace))) {
840
-
841
- // it's only now that we know the line is not part of a setext header:
842
- container = add_child(parser, container, NODE_HRULE, parser->first_nonspace + 1);
843
- container = finalize(parser, container);
844
- S_advance_offset(parser, &input, input.len - 1 - parser->offset, false);
845
-
846
- } else if ((matched = parse_list_marker(&input, parser->first_nonspace, &data)) &&
847
- (!indented || container->type == NODE_LIST)) {
848
- // Note that we can have new list items starting with >= 4
849
- // spaces indent, as long as the list container is still open.
850
-
851
- // compute padding:
852
- S_advance_offset(parser, &input, parser->first_nonspace + matched - parser->offset, false);
853
- i = 0;
854
- while (i <= 5 && peek_at(&input, parser->offset + i) == ' ') {
855
- i++;
856
- }
857
- // i = number of spaces after marker, up to 5
858
- if (i >= 5 || i < 1 ||
859
- S_is_line_end_char(peek_at(&input, parser->offset))) {
860
- data->padding = matched + 1;
861
- if (i > 0) {
862
- S_advance_offset(parser, &input, 1, false);
863
- }
864
- } else {
865
- data->padding = matched + i;
866
- S_advance_offset(parser, &input, i, true);
867
- }
868
-
869
- // check container; if it's a list, see if this list item
870
- // can continue the list; otherwise, create a list container.
871
-
872
- data->marker_offset = parser->indent;
873
-
874
- if (container->type != NODE_LIST ||
875
- !lists_match(&container->as.list, data)) {
876
- container = add_child(parser, container, NODE_LIST,
877
- parser->first_nonspace + 1);
878
-
879
- memcpy(&container->as.list, data, sizeof(*data));
880
- }
881
-
882
- // add the list item
883
- container = add_child(parser, container, NODE_ITEM,
884
- parser->first_nonspace + 1);
885
- /* TODO: static */
886
- memcpy(&container->as.list, data, sizeof(*data));
887
- free(data);
888
-
889
- } else if (indented && !maybe_lazy && !parser->blank) {
890
- S_advance_offset(parser, &input, CODE_INDENT, true);
891
- container = add_child(parser, container, NODE_CODE_BLOCK, parser->offset + 1);
892
- container->as.code.fenced = false;
893
- container->as.code.fence_char = 0;
894
- container->as.code.fence_length = 0;
895
- container->as.code.fence_offset = 0;
896
- container->as.code.info = cmark_chunk_literal("");
897
-
898
- } else {
899
- break;
900
- }
901
-
902
- if (accepts_lines(container->type)) {
903
- // if it's a line container, it can't contain other containers
904
- break;
905
- }
906
- maybe_lazy = false;
907
- }
908
-
909
- // what remains at parser->offset is a text line. add the text to the
910
- // appropriate container.
911
-
912
- S_find_first_nonspace(parser, &input);
913
-
914
- if (parser->blank && container->last_child) {
915
- container->last_child->last_line_blank = true;
916
- }
917
-
918
- // block quote lines are never blank as they start with >
919
- // and we don't count blanks in fenced code for purposes of tight/loose
920
- // lists or breaking out of lists. we also don't set last_line_blank
921
- // on an empty list item.
922
- container->last_line_blank = (parser->blank &&
923
- container->type != NODE_BLOCK_QUOTE &&
924
- container->type != NODE_HEADER &&
925
- !(container->type == NODE_CODE_BLOCK &&
926
- container->as.code.fenced) &&
927
- !(container->type == NODE_ITEM &&
928
- container->first_child == NULL &&
929
- container->start_line == parser->line_number));
930
-
931
- cmark_node *cont = container;
932
- while (cont->parent) {
933
- cont->parent->last_line_blank = false;
934
- cont = cont->parent;
935
- }
936
-
937
- if (parser->current != last_matched_container &&
938
- container == last_matched_container &&
939
- !parser->blank &&
940
- parser->current->type == NODE_PARAGRAPH &&
941
- cmark_strbuf_len(&parser->current->string_content) > 0) {
942
-
943
- add_line(parser->current, &input, parser->offset);
944
-
945
- } else { // not a lazy continuation
946
-
947
- // finalize any blocks that were not matched and set cur to container:
948
- while (parser->current != last_matched_container) {
949
- parser->current = finalize(parser, parser->current);
950
- assert(parser->current != NULL);
951
- }
952
-
953
- if (container->type == NODE_CODE_BLOCK) {
954
-
955
- add_line(container, &input, parser->offset);
956
-
957
- } else if (container->type == NODE_HTML) {
958
-
959
- add_line(container, &input, parser->offset);
960
-
961
- int matches_end_condition;
962
- switch (container->as.html_block_type) {
963
- case 1:
964
- // </script>, </style>, </pre>
965
- matches_end_condition =
966
- scan_html_block_end_1(&input, parser->first_nonspace);
967
- break;
968
- case 2:
969
- // -->
970
- matches_end_condition =
971
- scan_html_block_end_2(&input, parser->first_nonspace);
972
- break;
973
- case 3:
974
- // ?>
975
- matches_end_condition =
976
- scan_html_block_end_3(&input, parser->first_nonspace);
977
- break;
978
- case 4:
979
- // >
980
- matches_end_condition =
981
- scan_html_block_end_4(&input, parser->first_nonspace);
982
- break;
983
- case 5:
984
- // ]]>
985
- matches_end_condition =
986
- scan_html_block_end_5(&input, parser->first_nonspace);
987
- break;
988
- default:
989
- matches_end_condition = 0;
990
- break;
991
- }
992
-
993
- if (matches_end_condition) {
994
- container = finalize(parser, container);
995
- assert(parser->current != NULL);
996
- }
997
-
998
- } else if (parser->blank) {
999
-
1000
- // ??? do nothing
1001
-
1002
- } else if (accepts_lines(container->type)) {
1003
-
1004
- if (container->type == NODE_HEADER &&
1005
- container->as.header.setext == false) {
1006
- chop_trailing_hashtags(&input);
1007
- }
1008
- add_line(container, &input, parser->first_nonspace);
1009
-
1010
- } else {
1011
- // create paragraph container for line
1012
- container = add_child(parser, container, NODE_PARAGRAPH, parser->first_nonspace + 1);
1013
- add_line(container, &input, parser->first_nonspace);
1014
-
1015
- }
1016
-
1017
- parser->current = container;
1018
- }
584
+ static void S_process_line(cmark_parser *parser, const unsigned char *buffer,
585
+ bufsize_t bytes) {
586
+ cmark_node *last_matched_container;
587
+ bufsize_t matched = 0;
588
+ int lev = 0;
589
+ int i;
590
+ cmark_list *data = NULL;
591
+ bool all_matched = true;
592
+ cmark_node *container;
593
+ bool indented;
594
+ cmark_chunk input;
595
+ bool maybe_lazy;
596
+
597
+ if (parser->options & CMARK_OPT_VALIDATE_UTF8) {
598
+ cmark_utf8proc_check(parser->curline, buffer, bytes);
599
+ } else {
600
+ cmark_strbuf_put(parser->curline, buffer, bytes);
601
+ }
602
+ // ensure line ends with a newline:
603
+ if (bytes == 0 || !S_is_line_end_char(parser->curline->ptr[bytes - 1])) {
604
+ cmark_strbuf_putc(parser->curline, '\n');
605
+ }
606
+ parser->offset = 0;
607
+ parser->column = 0;
608
+ parser->blank = false;
609
+
610
+ input.data = parser->curline->ptr;
611
+ input.len = parser->curline->size;
612
+
613
+ // container starts at the document root.
614
+ container = parser->root;
615
+
616
+ parser->line_number++;
617
+
618
+ // for each containing node, try to parse the associated line start.
619
+ // bail out on failure: container will point to the last matching node.
620
+
621
+ while (container->last_child && container->last_child->open) {
622
+ container = container->last_child;
623
+
624
+ S_find_first_nonspace(parser, &input);
625
+
626
+ if (container->type == NODE_BLOCK_QUOTE) {
627
+ matched =
628
+ parser->indent <= 3 && peek_at(&input, parser->first_nonspace) == '>';
629
+ if (matched) {
630
+ S_advance_offset(parser, &input, parser->indent + 1, true);
631
+ if (peek_at(&input, parser->offset) == ' ')
632
+ parser->offset++;
633
+ } else {
634
+ all_matched = false;
635
+ }
636
+
637
+ } else if (container->type == NODE_ITEM) {
638
+ if (parser->indent >=
639
+ container->as.list.marker_offset + container->as.list.padding) {
640
+ S_advance_offset(parser, &input, container->as.list.marker_offset +
641
+ container->as.list.padding,
642
+ true);
643
+ } else if (parser->blank && container->first_child != NULL) {
644
+ // if container->first_child is NULL, then the opening line
645
+ // of the list item was blank after the list marker; in this
646
+ // case, we are done with the list item.
647
+ S_advance_offset(parser, &input,
648
+ parser->first_nonspace - parser->offset, false);
649
+ } else {
650
+ all_matched = false;
651
+ }
652
+
653
+ } else if (container->type == NODE_CODE_BLOCK) {
654
+
655
+ if (!container->as.code.fenced) { // indented
656
+ if (parser->indent >= CODE_INDENT) {
657
+ S_advance_offset(parser, &input, CODE_INDENT, true);
658
+ } else if (parser->blank) {
659
+ S_advance_offset(parser, &input,
660
+ parser->first_nonspace - parser->offset, false);
661
+ } else {
662
+ all_matched = false;
663
+ }
664
+ } else { // fenced
665
+ matched = 0;
666
+ if (parser->indent <= 3 && (peek_at(&input, parser->first_nonspace) ==
667
+ container->as.code.fence_char)) {
668
+ matched = scan_close_code_fence(&input, parser->first_nonspace);
669
+ }
670
+ if (matched >= container->as.code.fence_length) {
671
+ // closing fence - and since we're at
672
+ // the end of a line, we can return:
673
+ all_matched = false;
674
+ S_advance_offset(parser, &input, matched, false);
675
+ parser->current = finalize(parser, container);
676
+ goto finished;
677
+ } else {
678
+ // skip opt. spaces of fence parser->offset
679
+ i = container->as.code.fence_offset;
680
+ while (i > 0 && peek_at(&input, parser->offset) == ' ') {
681
+ S_advance_offset(parser, &input, 1, false);
682
+ i--;
683
+ }
684
+ }
685
+ }
686
+ } else if (container->type == NODE_HEADER) {
687
+
688
+ // a header can never contain more than one line
689
+ all_matched = false;
690
+
691
+ } else if (container->type == NODE_HTML) {
692
+
693
+ switch (container->as.html_block_type) {
694
+ case 1:
695
+ case 2:
696
+ case 3:
697
+ case 4:
698
+ case 5:
699
+ // these types of blocks can accept blanks
700
+ break;
701
+ case 6:
702
+ case 7:
703
+ if (parser->blank) {
704
+ all_matched = false;
705
+ }
706
+ break;
707
+ default:
708
+ fprintf(stderr, "Error (%s:%d): Unknown HTML block type %d\n", __FILE__,
709
+ __LINE__, container->as.html_block_type);
710
+ exit(1);
711
+ }
712
+
713
+ } else if (container->type == NODE_PARAGRAPH) {
714
+
715
+ if (parser->blank) {
716
+ all_matched = false;
717
+ }
718
+ }
719
+
720
+ if (!all_matched) {
721
+ container = container->parent; // back up to last matching node
722
+ break;
723
+ }
724
+ }
725
+
726
+ last_matched_container = container;
727
+
728
+ // check to see if we've hit 2nd blank line, break out of list:
729
+ if (parser->blank && container->last_line_blank) {
730
+ break_out_of_lists(parser, &container);
731
+ }
732
+
733
+ maybe_lazy = parser->current->type == NODE_PARAGRAPH;
734
+ // try new container starts:
735
+ while (container->type != NODE_CODE_BLOCK && container->type != NODE_HTML) {
736
+
737
+ S_find_first_nonspace(parser, &input);
738
+ indented = parser->indent >= CODE_INDENT;
739
+
740
+ if (!indented && peek_at(&input, parser->first_nonspace) == '>') {
741
+
742
+ S_advance_offset(parser, &input,
743
+ parser->first_nonspace + 1 - parser->offset, false);
744
+ // optional following character
745
+ if (peek_at(&input, parser->offset) == ' ')
746
+ S_advance_offset(parser, &input, 1, false);
747
+ container =
748
+ add_child(parser, container, NODE_BLOCK_QUOTE, parser->offset + 1);
749
+
750
+ } else if (!indented && (matched = scan_atx_header_start(
751
+ &input, parser->first_nonspace))) {
752
+
753
+ S_advance_offset(parser, &input,
754
+ parser->first_nonspace + matched - parser->offset,
755
+ false);
756
+ container = add_child(parser, container, NODE_HEADER, parser->offset + 1);
757
+
758
+ bufsize_t hashpos =
759
+ cmark_chunk_strchr(&input, '#', parser->first_nonspace);
760
+ int level = 0;
761
+
762
+ while (peek_at(&input, hashpos) == '#') {
763
+ level++;
764
+ hashpos++;
765
+ }
766
+ container->as.header.level = level;
767
+ container->as.header.setext = false;
768
+
769
+ } else if (!indented && (matched = scan_open_code_fence(
770
+ &input, parser->first_nonspace))) {
771
+
772
+ container = add_child(parser, container, NODE_CODE_BLOCK,
773
+ parser->first_nonspace + 1);
774
+ container->as.code.fenced = true;
775
+ container->as.code.fence_char = peek_at(&input, parser->first_nonspace);
776
+ container->as.code.fence_length = matched;
777
+ container->as.code.fence_offset = (int8_t)(parser->first_nonspace - parser->offset);
778
+ container->as.code.info = cmark_chunk_literal("");
779
+ S_advance_offset(parser, &input,
780
+ parser->first_nonspace + matched - parser->offset,
781
+ false);
782
+
783
+ } else if (!indented && ((matched = scan_html_block_start(
784
+ &input, parser->first_nonspace)) ||
785
+ (container->type != NODE_PARAGRAPH &&
786
+ (matched = scan_html_block_start_7(
787
+ &input, parser->first_nonspace))))) {
788
+
789
+ container =
790
+ add_child(parser, container, NODE_HTML, parser->first_nonspace + 1);
791
+ container->as.html_block_type = matched;
792
+ // note, we don't adjust parser->offset because the tag is part of the
793
+ // text
794
+
795
+ } else if (!indented && container->type == NODE_PARAGRAPH &&
796
+ (lev =
797
+ scan_setext_header_line(&input, parser->first_nonspace)) &&
798
+ // check that there is only one line in the paragraph:
799
+ (cmark_strbuf_strrchr(
800
+ &container->string_content, '\n',
801
+ cmark_strbuf_len(&container->string_content) - 2) < 0)) {
802
+
803
+ container->type = NODE_HEADER;
804
+ container->as.header.level = lev;
805
+ container->as.header.setext = true;
806
+ S_advance_offset(parser, &input, input.len - 1 - parser->offset, false);
807
+
808
+ } else if (!indented &&
809
+ !(container->type == NODE_PARAGRAPH && !all_matched) &&
810
+ (matched = scan_hrule(&input, parser->first_nonspace))) {
811
+
812
+ // it's only now that we know the line is not part of a setext header:
813
+ container =
814
+ add_child(parser, container, NODE_HRULE, parser->first_nonspace + 1);
815
+ S_advance_offset(parser, &input, input.len - 1 - parser->offset, false);
816
+
817
+ } else if ((matched =
818
+ parse_list_marker(&input, parser->first_nonspace, &data)) &&
819
+ (!indented || container->type == NODE_LIST)) {
820
+ // Note that we can have new list items starting with >= 4
821
+ // spaces indent, as long as the list container is still open.
822
+
823
+ // compute padding:
824
+ S_advance_offset(parser, &input,
825
+ parser->first_nonspace + matched - parser->offset,
826
+ false);
827
+ i = 0;
828
+ while (i <= 5 && peek_at(&input, parser->offset + i) == ' ') {
829
+ i++;
830
+ }
831
+ // i = number of spaces after marker, up to 5
832
+ if (i >= 5 || i < 1 ||
833
+ S_is_line_end_char(peek_at(&input, parser->offset))) {
834
+ data->padding = matched + 1;
835
+ if (i > 0) {
836
+ S_advance_offset(parser, &input, 1, false);
837
+ }
838
+ } else {
839
+ data->padding = matched + i;
840
+ S_advance_offset(parser, &input, i, true);
841
+ }
842
+
843
+ // check container; if it's a list, see if this list item
844
+ // can continue the list; otherwise, create a list container.
845
+
846
+ data->marker_offset = parser->indent;
847
+
848
+ if (container->type != NODE_LIST ||
849
+ !lists_match(&container->as.list, data)) {
850
+ container =
851
+ add_child(parser, container, NODE_LIST, parser->first_nonspace + 1);
852
+
853
+ memcpy(&container->as.list, data, sizeof(*data));
854
+ }
855
+
856
+ // add the list item
857
+ container =
858
+ add_child(parser, container, NODE_ITEM, parser->first_nonspace + 1);
859
+ /* TODO: static */
860
+ memcpy(&container->as.list, data, sizeof(*data));
861
+ free(data);
862
+
863
+ } else if (indented && !maybe_lazy && !parser->blank) {
864
+ S_advance_offset(parser, &input, CODE_INDENT, true);
865
+ container =
866
+ add_child(parser, container, NODE_CODE_BLOCK, parser->offset + 1);
867
+ container->as.code.fenced = false;
868
+ container->as.code.fence_char = 0;
869
+ container->as.code.fence_length = 0;
870
+ container->as.code.fence_offset = 0;
871
+ container->as.code.info = cmark_chunk_literal("");
872
+
873
+ } else {
874
+ break;
875
+ }
876
+
877
+ if (accepts_lines(container->type)) {
878
+ // if it's a line container, it can't contain other containers
879
+ break;
880
+ }
881
+ maybe_lazy = false;
882
+ }
883
+
884
+ // what remains at parser->offset is a text line. add the text to the
885
+ // appropriate container.
886
+
887
+ S_find_first_nonspace(parser, &input);
888
+
889
+ if (parser->blank && container->last_child) {
890
+ container->last_child->last_line_blank = true;
891
+ }
892
+
893
+ // block quote lines are never blank as they start with >
894
+ // and we don't count blanks in fenced code for purposes of tight/loose
895
+ // lists or breaking out of lists. we also don't set last_line_blank
896
+ // on an empty list item.
897
+ container->last_line_blank =
898
+ (parser->blank && container->type != NODE_BLOCK_QUOTE &&
899
+ container->type != NODE_HEADER &&
900
+ container->type != NODE_HRULE &&
901
+ !(container->type == NODE_CODE_BLOCK && container->as.code.fenced) &&
902
+ !(container->type == NODE_ITEM && container->first_child == NULL &&
903
+ container->start_line == parser->line_number));
904
+
905
+ cmark_node *cont = container;
906
+ while (cont->parent) {
907
+ cont->parent->last_line_blank = false;
908
+ cont = cont->parent;
909
+ }
910
+
911
+ if (parser->current != last_matched_container &&
912
+ container == last_matched_container && !parser->blank &&
913
+ parser->current->type == NODE_PARAGRAPH &&
914
+ cmark_strbuf_len(&parser->current->string_content) > 0) {
915
+
916
+ add_line(parser->current, &input, parser->offset);
917
+
918
+ } else { // not a lazy continuation
919
+
920
+ // finalize any blocks that were not matched and set cur to container:
921
+ while (parser->current != last_matched_container) {
922
+ parser->current = finalize(parser, parser->current);
923
+ assert(parser->current != NULL);
924
+ }
925
+
926
+ if (container->type == NODE_CODE_BLOCK) {
927
+
928
+ add_line(container, &input, parser->offset);
929
+
930
+ } else if (container->type == NODE_HTML) {
931
+
932
+ add_line(container, &input, parser->offset);
933
+
934
+ int matches_end_condition;
935
+ switch (container->as.html_block_type) {
936
+ case 1:
937
+ // </script>, </style>, </pre>
938
+ matches_end_condition =
939
+ scan_html_block_end_1(&input, parser->first_nonspace);
940
+ break;
941
+ case 2:
942
+ // -->
943
+ matches_end_condition =
944
+ scan_html_block_end_2(&input, parser->first_nonspace);
945
+ break;
946
+ case 3:
947
+ // ?>
948
+ matches_end_condition =
949
+ scan_html_block_end_3(&input, parser->first_nonspace);
950
+ break;
951
+ case 4:
952
+ // >
953
+ matches_end_condition =
954
+ scan_html_block_end_4(&input, parser->first_nonspace);
955
+ break;
956
+ case 5:
957
+ // ]]>
958
+ matches_end_condition =
959
+ scan_html_block_end_5(&input, parser->first_nonspace);
960
+ break;
961
+ default:
962
+ matches_end_condition = 0;
963
+ break;
964
+ }
965
+
966
+ if (matches_end_condition) {
967
+ container = finalize(parser, container);
968
+ assert(parser->current != NULL);
969
+ }
970
+
971
+ } else if (parser->blank) {
972
+
973
+ // ??? do nothing
974
+
975
+ } else if (accepts_lines(container->type)) {
976
+
977
+ if (container->type == NODE_HEADER &&
978
+ container->as.header.setext == false) {
979
+ chop_trailing_hashtags(&input);
980
+ }
981
+ add_line(container, &input, parser->first_nonspace);
982
+
983
+ } else {
984
+ // create paragraph container for line
985
+ container = add_child(parser, container, NODE_PARAGRAPH,
986
+ parser->first_nonspace + 1);
987
+ add_line(container, &input, parser->first_nonspace);
988
+ }
989
+
990
+ parser->current = container;
991
+ }
1019
992
  finished:
1020
- parser->last_line_length = parser->curline->size;
1021
- if (parser->last_line_length &&
1022
- parser->curline->ptr[parser->last_line_length - 1] == '\n')
1023
- parser->last_line_length -= 1;
1024
- if (parser->last_line_length &&
1025
- parser->curline->ptr[parser->last_line_length - 1] == '\r')
1026
- parser->last_line_length -= 1;
1027
-
1028
- cmark_strbuf_clear(parser->curline);
1029
-
993
+ parser->last_line_length = parser->curline->size;
994
+ if (parser->last_line_length &&
995
+ parser->curline->ptr[parser->last_line_length - 1] == '\n')
996
+ parser->last_line_length -= 1;
997
+ if (parser->last_line_length &&
998
+ parser->curline->ptr[parser->last_line_length - 1] == '\r')
999
+ parser->last_line_length -= 1;
1000
+
1001
+ cmark_strbuf_clear(parser->curline);
1030
1002
  }
1031
1003
 
1032
- cmark_node *cmark_parser_finish(cmark_parser *parser)
1033
- {
1034
- if (parser->linebuf->size) {
1035
- S_process_line(parser, parser->linebuf->ptr,
1036
- parser->linebuf->size);
1037
- cmark_strbuf_clear(parser->linebuf);
1038
- }
1004
+ cmark_node *cmark_parser_finish(cmark_parser *parser) {
1005
+ if (parser->linebuf->size) {
1006
+ S_process_line(parser, parser->linebuf->ptr, parser->linebuf->size);
1007
+ cmark_strbuf_clear(parser->linebuf);
1008
+ }
1039
1009
 
1040
- finalize_document(parser);
1010
+ finalize_document(parser);
1041
1011
 
1042
- if (parser->options & CMARK_OPT_NORMALIZE) {
1043
- cmark_consolidate_text_nodes(parser->root);
1044
- }
1012
+ if (parser->options & CMARK_OPT_NORMALIZE) {
1013
+ cmark_consolidate_text_nodes(parser->root);
1014
+ }
1045
1015
 
1046
- cmark_strbuf_free(parser->curline);
1016
+ cmark_strbuf_free(parser->curline);
1047
1017
 
1048
1018
  #if CMARK_DEBUG_NODES
1049
- if (cmark_node_check(parser->root, stderr)) {
1050
- abort();
1051
- }
1019
+ if (cmark_node_check(parser->root, stderr)) {
1020
+ abort();
1021
+ }
1052
1022
  #endif
1053
- return parser->root;
1023
+ return parser->root;
1054
1024
  }