Line | Count | Source (jump to first uncovered line) |
1 | | #include <stdbool.h> |
2 | | #include <stdlib.h> |
3 | | #include <string.h> |
4 | | |
5 | | #include "node.h" |
6 | | |
7 | | static void S_node_unlink(cmark_node *node); |
8 | | |
9 | 0 | static inline bool S_is_block(cmark_node *node) { |
10 | 0 | if (node == NULL) { |
11 | 0 | return false; |
12 | 0 | } |
13 | 0 | return node->type >= CMARK_NODE_FIRST_BLOCK && |
14 | 0 | node->type <= CMARK_NODE_LAST_BLOCK; |
15 | 0 | } |
16 | | |
17 | 461k | static inline bool S_is_inline(cmark_node *node) { |
18 | 461k | if (node == NULL) { |
19 | 0 | return false; |
20 | 0 | } |
21 | 461k | return node->type >= CMARK_NODE_FIRST_INLINE && |
22 | 461k | node->type <= CMARK_NODE_LAST_INLINE; |
23 | 461k | } |
24 | | |
25 | 461k | static bool S_can_contain(cmark_node *node, cmark_node *child) { |
26 | 461k | if (node == NULL || child == NULL || node == child) { |
27 | 0 | return false; |
28 | 0 | } |
29 | | |
30 | | // Verify that child is not an ancestor of node. |
31 | 461k | if (child->first_child != NULL) { |
32 | 0 | cmark_node *cur = node->parent; |
33 | |
|
34 | 0 | while (cur != NULL) { |
35 | 0 | if (cur == child) { |
36 | 0 | return false; |
37 | 0 | } |
38 | 0 | cur = cur->parent; |
39 | 0 | } |
40 | 0 | } |
41 | | |
42 | 461k | if (child->type == CMARK_NODE_DOCUMENT) { |
43 | 0 | return false; |
44 | 0 | } |
45 | | |
46 | 461k | switch (node->type) { |
47 | 0 | case CMARK_NODE_DOCUMENT: |
48 | 0 | case CMARK_NODE_BLOCK_QUOTE: |
49 | 0 | case CMARK_NODE_ITEM: |
50 | 0 | return S_is_block(child) && child->type != CMARK_NODE_ITEM; |
51 | | |
52 | 0 | case CMARK_NODE_LIST: |
53 | 0 | return child->type == CMARK_NODE_ITEM; |
54 | | |
55 | 0 | case CMARK_NODE_CUSTOM_BLOCK: |
56 | 0 | return true; |
57 | | |
58 | 450k | case CMARK_NODE_PARAGRAPH: |
59 | 461k | case CMARK_NODE_HEADING: |
60 | 461k | case CMARK_NODE_EMPH: |
61 | 461k | case CMARK_NODE_STRONG: |
62 | 461k | case CMARK_NODE_LINK: |
63 | 461k | case CMARK_NODE_IMAGE: |
64 | 461k | case CMARK_NODE_CUSTOM_INLINE: |
65 | 461k | return S_is_inline(child); |
66 | | |
67 | 0 | default: |
68 | 0 | break; |
69 | 461k | } |
70 | | |
71 | 0 | return false; |
72 | 461k | } |
73 | | |
74 | 0 | cmark_node *cmark_node_new_with_mem(cmark_node_type type, cmark_mem *mem) { |
75 | 0 | cmark_node *node = (cmark_node *)mem->calloc(1, sizeof(*node)); |
76 | 0 | node->mem = mem; |
77 | 0 | node->type = (uint16_t)type; |
78 | |
|
79 | 0 | switch (node->type) { |
80 | 0 | case CMARK_NODE_HEADING: |
81 | 0 | node->as.heading.level = 1; |
82 | 0 | break; |
83 | | |
84 | 0 | case CMARK_NODE_LIST: { |
85 | 0 | cmark_list *list = &node->as.list; |
86 | 0 | list->list_type = CMARK_BULLET_LIST; |
87 | 0 | list->start = 0; |
88 | 0 | list->tight = false; |
89 | 0 | break; |
90 | 0 | } |
91 | | |
92 | 0 | default: |
93 | 0 | break; |
94 | 0 | } |
95 | | |
96 | 0 | return node; |
97 | 0 | } |
98 | | |
99 | 0 | cmark_node *cmark_node_new(cmark_node_type type) { |
100 | 0 | extern cmark_mem DEFAULT_MEM_ALLOCATOR; |
101 | 0 | return cmark_node_new_with_mem(type, &DEFAULT_MEM_ALLOCATOR); |
102 | 0 | } |
103 | | |
104 | | // Free a cmark_node list and any children. |
105 | 50.4M | static void S_free_nodes(cmark_node *e) { |
106 | 50.4M | cmark_mem *mem = e->mem; |
107 | 50.4M | cmark_node *next; |
108 | 128M | while (e != NULL) { |
109 | 77.5M | switch (e->type) { |
110 | 69.5k | case CMARK_NODE_CODE_BLOCK: |
111 | 69.5k | mem->free(e->data); |
112 | 69.5k | mem->free(e->as.code.info); |
113 | 69.5k | break; |
114 | 59.7M | case CMARK_NODE_TEXT: |
115 | 60.6M | case CMARK_NODE_HTML_INLINE: |
116 | 60.7M | case CMARK_NODE_CODE: |
117 | 60.9M | case CMARK_NODE_HTML_BLOCK: |
118 | 60.9M | mem->free(e->data); |
119 | 60.9M | break; |
120 | 590k | case CMARK_NODE_LINK: |
121 | 597k | case CMARK_NODE_IMAGE: |
122 | 597k | mem->free(e->as.link.url); |
123 | 597k | mem->free(e->as.link.title); |
124 | 597k | break; |
125 | 0 | case CMARK_NODE_CUSTOM_BLOCK: |
126 | 0 | case CMARK_NODE_CUSTOM_INLINE: |
127 | 0 | mem->free(e->as.custom.on_enter); |
128 | 0 | mem->free(e->as.custom.on_exit); |
129 | 0 | break; |
130 | 15.9M | default: |
131 | 15.9M | break; |
132 | 77.5M | } |
133 | 77.5M | if (e->last_child) { |
134 | | // Splice children into list |
135 | 9.25M | e->last_child->next = e->next; |
136 | 9.25M | e->next = e->first_child; |
137 | 9.25M | } |
138 | 77.5M | next = e->next; |
139 | 77.5M | mem->free(e); |
140 | 77.5M | e = next; |
141 | 77.5M | } |
142 | 50.4M | } |
143 | | |
144 | 50.4M | void cmark_node_free(cmark_node *node) { |
145 | 50.4M | S_node_unlink(node); |
146 | 50.4M | node->next = NULL; |
147 | 50.4M | S_free_nodes(node); |
148 | 50.4M | } |
149 | | |
150 | 0 | cmark_node_type cmark_node_get_type(cmark_node *node) { |
151 | 0 | if (node == NULL) { |
152 | 0 | return CMARK_NODE_NONE; |
153 | 0 | } else { |
154 | 0 | return (cmark_node_type)node->type; |
155 | 0 | } |
156 | 0 | } |
157 | | |
158 | 46.8M | const char *cmark_node_get_type_string(cmark_node *node) { |
159 | 46.8M | if (node == NULL) { |
160 | 0 | return "NONE"; |
161 | 0 | } |
162 | | |
163 | 46.8M | switch (node->type) { |
164 | 0 | case CMARK_NODE_NONE: |
165 | 0 | return "none"; |
166 | 81.1k | case CMARK_NODE_DOCUMENT: |
167 | 81.1k | return "document"; |
168 | 6.76M | case CMARK_NODE_BLOCK_QUOTE: |
169 | 6.76M | return "block_quote"; |
170 | 4.23M | case CMARK_NODE_LIST: |
171 | 4.23M | return "list"; |
172 | 2.96M | case CMARK_NODE_ITEM: |
173 | 2.96M | return "item"; |
174 | 139k | case CMARK_NODE_CODE_BLOCK: |
175 | 139k | return "code_block"; |
176 | 307k | case CMARK_NODE_HTML_BLOCK: |
177 | 307k | return "html_block"; |
178 | 0 | case CMARK_NODE_CUSTOM_BLOCK: |
179 | 0 | return "custom_block"; |
180 | 2.81M | case CMARK_NODE_PARAGRAPH: |
181 | 2.81M | return "paragraph"; |
182 | 300k | case CMARK_NODE_HEADING: |
183 | 300k | return "heading"; |
184 | 65.4k | case CMARK_NODE_THEMATIC_BREAK: |
185 | 65.4k | return "thematic_break"; |
186 | 18.6M | case CMARK_NODE_TEXT: |
187 | 18.6M | return "text"; |
188 | 5.47M | case CMARK_NODE_SOFTBREAK: |
189 | 5.47M | return "softbreak"; |
190 | 24.2k | case CMARK_NODE_LINEBREAK: |
191 | 24.2k | return "linebreak"; |
192 | 319k | case CMARK_NODE_CODE: |
193 | 319k | return "code"; |
194 | 1.62M | case CMARK_NODE_HTML_INLINE: |
195 | 1.62M | return "html_inline"; |
196 | 0 | case CMARK_NODE_CUSTOM_INLINE: |
197 | 0 | return "custom_inline"; |
198 | 1.13M | case CMARK_NODE_EMPH: |
199 | 1.13M | return "emph"; |
200 | 760k | case CMARK_NODE_STRONG: |
201 | 760k | return "strong"; |
202 | 1.16M | case CMARK_NODE_LINK: |
203 | 1.16M | return "link"; |
204 | 14.1k | case CMARK_NODE_IMAGE: |
205 | 14.1k | return "image"; |
206 | 46.8M | } |
207 | | |
208 | 0 | return "<unknown>"; |
209 | 46.8M | } |
210 | | |
211 | 0 | cmark_node *cmark_node_next(cmark_node *node) { |
212 | 0 | if (node == NULL) { |
213 | 0 | return NULL; |
214 | 0 | } else { |
215 | 0 | return node->next; |
216 | 0 | } |
217 | 0 | } |
218 | | |
219 | 0 | cmark_node *cmark_node_previous(cmark_node *node) { |
220 | 0 | if (node == NULL) { |
221 | 0 | return NULL; |
222 | 0 | } else { |
223 | 0 | return node->prev; |
224 | 0 | } |
225 | 0 | } |
226 | | |
227 | 5.64M | cmark_node *cmark_node_parent(cmark_node *node) { |
228 | 5.64M | if (node == NULL) { |
229 | 0 | return NULL; |
230 | 5.64M | } else { |
231 | 5.64M | return node->parent; |
232 | 5.64M | } |
233 | 5.64M | } |
234 | | |
235 | 0 | cmark_node *cmark_node_first_child(cmark_node *node) { |
236 | 0 | if (node == NULL) { |
237 | 0 | return NULL; |
238 | 0 | } else { |
239 | 0 | return node->first_child; |
240 | 0 | } |
241 | 0 | } |
242 | | |
243 | 0 | cmark_node *cmark_node_last_child(cmark_node *node) { |
244 | 0 | if (node == NULL) { |
245 | 0 | return NULL; |
246 | 0 | } else { |
247 | 0 | return node->last_child; |
248 | 0 | } |
249 | 0 | } |
250 | | |
251 | | static bufsize_t cmark_set_cstr(cmark_mem *mem, unsigned char **dst, |
252 | 1.31M | const char *src) { |
253 | 1.31M | unsigned char *old = *dst; |
254 | 1.31M | bufsize_t len; |
255 | | |
256 | 1.31M | if (src && src[0]) { |
257 | 1.31M | len = (bufsize_t)strlen(src); |
258 | 1.31M | *dst = (unsigned char *)mem->realloc(NULL, len + 1); |
259 | 1.31M | memcpy(*dst, src, len + 1); |
260 | 1.31M | } else { |
261 | 0 | len = 0; |
262 | 0 | *dst = NULL; |
263 | 0 | } |
264 | 1.31M | if (old) { |
265 | 1.31M | mem->free(old); |
266 | 1.31M | } |
267 | | |
268 | 1.31M | return len; |
269 | 1.31M | } |
270 | | |
271 | 0 | void *cmark_node_get_user_data(cmark_node *node) { |
272 | 0 | if (node == NULL) { |
273 | 0 | return NULL; |
274 | 0 | } else { |
275 | 0 | return node->user_data; |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | 0 | int cmark_node_set_user_data(cmark_node *node, void *user_data) { |
280 | 0 | if (node == NULL) { |
281 | 0 | return 0; |
282 | 0 | } |
283 | 0 | node->user_data = user_data; |
284 | 0 | return 1; |
285 | 0 | } |
286 | | |
287 | 29.7M | const char *cmark_node_get_literal(cmark_node *node) { |
288 | 29.7M | if (node == NULL) { |
289 | 0 | return NULL; |
290 | 0 | } |
291 | | |
292 | 29.7M | switch (node->type) { |
293 | 153k | case CMARK_NODE_HTML_BLOCK: |
294 | 28.0M | case CMARK_NODE_TEXT: |
295 | 28.8M | case CMARK_NODE_HTML_INLINE: |
296 | 29.4M | case CMARK_NODE_CODE: |
297 | 29.7M | case CMARK_NODE_CODE_BLOCK: |
298 | 29.7M | return node->data ? (char *)node->data : ""; |
299 | | |
300 | 0 | default: |
301 | 0 | break; |
302 | 29.7M | } |
303 | | |
304 | 0 | return NULL; |
305 | 29.7M | } |
306 | | |
307 | 1.31M | int cmark_node_set_literal(cmark_node *node, const char *content) { |
308 | 1.31M | if (node == NULL) { |
309 | 0 | return 0; |
310 | 0 | } |
311 | | |
312 | 1.31M | switch (node->type) { |
313 | 0 | case CMARK_NODE_HTML_BLOCK: |
314 | 1.31M | case CMARK_NODE_TEXT: |
315 | 1.31M | case CMARK_NODE_HTML_INLINE: |
316 | 1.31M | case CMARK_NODE_CODE: |
317 | 1.31M | case CMARK_NODE_CODE_BLOCK: |
318 | 1.31M | node->len = cmark_set_cstr(node->mem, &node->data, content); |
319 | 1.31M | return 1; |
320 | | |
321 | 0 | default: |
322 | 0 | break; |
323 | 1.31M | } |
324 | | |
325 | 0 | return 0; |
326 | 1.31M | } |
327 | | |
328 | 562k | int cmark_node_get_heading_level(cmark_node *node) { |
329 | 562k | if (node == NULL) { |
330 | 0 | return 0; |
331 | 0 | } |
332 | | |
333 | 562k | switch (node->type) { |
334 | 562k | case CMARK_NODE_HEADING: |
335 | 562k | return node->as.heading.level; |
336 | | |
337 | 0 | default: |
338 | 0 | break; |
339 | 562k | } |
340 | | |
341 | 0 | return 0; |
342 | 562k | } |
343 | | |
344 | 0 | int cmark_node_set_heading_level(cmark_node *node, int level) { |
345 | 0 | if (node == NULL || level < 1 || level > 6) { |
346 | 0 | return 0; |
347 | 0 | } |
348 | | |
349 | 0 | switch (node->type) { |
350 | 0 | case CMARK_NODE_HEADING: |
351 | 0 | node->as.heading.level = level; |
352 | 0 | return 1; |
353 | | |
354 | 0 | default: |
355 | 0 | break; |
356 | 0 | } |
357 | | |
358 | 0 | return 0; |
359 | 0 | } |
360 | | |
361 | 15.4M | cmark_list_type cmark_node_get_list_type(cmark_node *node) { |
362 | 15.4M | if (node == NULL) { |
363 | 0 | return CMARK_NO_LIST; |
364 | 0 | } |
365 | | |
366 | 15.4M | if (node->type == CMARK_NODE_LIST) { |
367 | 15.4M | return (cmark_list_type)node->as.list.list_type; |
368 | 15.4M | } else { |
369 | 0 | return CMARK_NO_LIST; |
370 | 0 | } |
371 | 15.4M | } |
372 | | |
373 | 0 | int cmark_node_set_list_type(cmark_node *node, cmark_list_type type) { |
374 | 0 | if (!(type == CMARK_BULLET_LIST || type == CMARK_ORDERED_LIST)) { |
375 | 0 | return 0; |
376 | 0 | } |
377 | | |
378 | 0 | if (node == NULL) { |
379 | 0 | return 0; |
380 | 0 | } |
381 | | |
382 | 0 | if (node->type == CMARK_NODE_LIST) { |
383 | 0 | node->as.list.list_type = (unsigned char)type; |
384 | 0 | return 1; |
385 | 0 | } else { |
386 | 0 | return 0; |
387 | 0 | } |
388 | 0 | } |
389 | | |
390 | 66.0k | cmark_delim_type cmark_node_get_list_delim(cmark_node *node) { |
391 | 66.0k | if (node == NULL) { |
392 | 0 | return CMARK_NO_DELIM; |
393 | 0 | } |
394 | | |
395 | 66.0k | if (node->type == CMARK_NODE_LIST) { |
396 | 66.0k | return (cmark_delim_type)node->as.list.delimiter; |
397 | 66.0k | } else { |
398 | 0 | return CMARK_NO_DELIM; |
399 | 0 | } |
400 | 66.0k | } |
401 | | |
402 | 0 | int cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim) { |
403 | 0 | if (!(delim == CMARK_PERIOD_DELIM || delim == CMARK_PAREN_DELIM)) { |
404 | 0 | return 0; |
405 | 0 | } |
406 | | |
407 | 0 | if (node == NULL) { |
408 | 0 | return 0; |
409 | 0 | } |
410 | | |
411 | 0 | if (node->type == CMARK_NODE_LIST) { |
412 | 0 | node->as.list.delimiter = (unsigned char)delim; |
413 | 0 | return 1; |
414 | 0 | } else { |
415 | 0 | return 0; |
416 | 0 | } |
417 | 0 | } |
418 | | |
419 | 2.20M | int cmark_node_get_list_start(cmark_node *node) { |
420 | 2.20M | if (node == NULL) { |
421 | 0 | return 0; |
422 | 0 | } |
423 | | |
424 | 2.20M | if (node->type == CMARK_NODE_LIST) { |
425 | 2.20M | return node->as.list.start; |
426 | 2.20M | } else { |
427 | 0 | return 0; |
428 | 0 | } |
429 | 2.20M | } |
430 | | |
431 | 0 | int cmark_node_set_list_start(cmark_node *node, int start) { |
432 | 0 | if (node == NULL || start < 0) { |
433 | 0 | return 0; |
434 | 0 | } |
435 | | |
436 | 0 | if (node->type == CMARK_NODE_LIST) { |
437 | 0 | node->as.list.start = start; |
438 | 0 | return 1; |
439 | 0 | } else { |
440 | 0 | return 0; |
441 | 0 | } |
442 | 0 | } |
443 | | |
444 | 2.11M | int cmark_node_get_list_tight(cmark_node *node) { |
445 | 2.11M | if (node == NULL) { |
446 | 0 | return 0; |
447 | 0 | } |
448 | | |
449 | 2.11M | if (node->type == CMARK_NODE_LIST) { |
450 | 2.11M | return node->as.list.tight; |
451 | 2.11M | } else { |
452 | 0 | return 0; |
453 | 0 | } |
454 | 2.11M | } |
455 | | |
456 | 0 | int cmark_node_set_list_tight(cmark_node *node, int tight) { |
457 | 0 | if (node == NULL) { |
458 | 0 | return 0; |
459 | 0 | } |
460 | | |
461 | 0 | if (node->type == CMARK_NODE_LIST) { |
462 | 0 | node->as.list.tight = tight == 1; |
463 | 0 | return 1; |
464 | 0 | } else { |
465 | 0 | return 0; |
466 | 0 | } |
467 | 0 | } |
468 | | |
469 | 69.5k | const char *cmark_node_get_fence_info(cmark_node *node) { |
470 | 69.5k | if (node == NULL) { |
471 | 0 | return NULL; |
472 | 0 | } |
473 | | |
474 | 69.5k | if (node->type == CMARK_NODE_CODE_BLOCK) { |
475 | 69.5k | return node->as.code.info ? (char *)node->as.code.info : ""; |
476 | 69.5k | } else { |
477 | 0 | return NULL; |
478 | 0 | } |
479 | 69.5k | } |
480 | | |
481 | 0 | int cmark_node_set_fence_info(cmark_node *node, const char *info) { |
482 | 0 | if (node == NULL) { |
483 | 0 | return 0; |
484 | 0 | } |
485 | | |
486 | 0 | if (node->type == CMARK_NODE_CODE_BLOCK) { |
487 | 0 | cmark_set_cstr(node->mem, &node->as.code.info, info); |
488 | 0 | return 1; |
489 | 0 | } else { |
490 | 0 | return 0; |
491 | 0 | } |
492 | 0 | } |
493 | | |
494 | 2.50M | const char *cmark_node_get_url(cmark_node *node) { |
495 | 2.50M | if (node == NULL) { |
496 | 0 | return NULL; |
497 | 0 | } |
498 | | |
499 | 2.50M | switch (node->type) { |
500 | 2.49M | case CMARK_NODE_LINK: |
501 | 2.50M | case CMARK_NODE_IMAGE: |
502 | 2.50M | return node->as.link.url ? (char *)node->as.link.url : ""; |
503 | 0 | default: |
504 | 0 | break; |
505 | 2.50M | } |
506 | | |
507 | 0 | return NULL; |
508 | 2.50M | } |
509 | | |
510 | 0 | int cmark_node_set_url(cmark_node *node, const char *url) { |
511 | 0 | if (node == NULL) { |
512 | 0 | return 0; |
513 | 0 | } |
514 | | |
515 | 0 | switch (node->type) { |
516 | 0 | case CMARK_NODE_LINK: |
517 | 0 | case CMARK_NODE_IMAGE: |
518 | 0 | cmark_set_cstr(node->mem, &node->as.link.url, url); |
519 | 0 | return 1; |
520 | 0 | default: |
521 | 0 | break; |
522 | 0 | } |
523 | | |
524 | 0 | return 0; |
525 | 0 | } |
526 | | |
527 | 660k | const char *cmark_node_get_title(cmark_node *node) { |
528 | 660k | if (node == NULL) { |
529 | 0 | return NULL; |
530 | 0 | } |
531 | | |
532 | 660k | switch (node->type) { |
533 | 653k | case CMARK_NODE_LINK: |
534 | 660k | case CMARK_NODE_IMAGE: |
535 | 660k | return node->as.link.title ? (char *)node->as.link.title : ""; |
536 | 0 | default: |
537 | 0 | break; |
538 | 660k | } |
539 | | |
540 | 0 | return NULL; |
541 | 660k | } |
542 | | |
543 | 0 | int cmark_node_set_title(cmark_node *node, const char *title) { |
544 | 0 | if (node == NULL) { |
545 | 0 | return 0; |
546 | 0 | } |
547 | | |
548 | 0 | switch (node->type) { |
549 | 0 | case CMARK_NODE_LINK: |
550 | 0 | case CMARK_NODE_IMAGE: |
551 | 0 | cmark_set_cstr(node->mem, &node->as.link.title, title); |
552 | 0 | return 1; |
553 | 0 | default: |
554 | 0 | break; |
555 | 0 | } |
556 | | |
557 | 0 | return 0; |
558 | 0 | } |
559 | | |
560 | 0 | const char *cmark_node_get_on_enter(cmark_node *node) { |
561 | 0 | if (node == NULL) { |
562 | 0 | return NULL; |
563 | 0 | } |
564 | | |
565 | 0 | switch (node->type) { |
566 | 0 | case CMARK_NODE_CUSTOM_INLINE: |
567 | 0 | case CMARK_NODE_CUSTOM_BLOCK: |
568 | 0 | return node->as.custom.on_enter ? (char *)node->as.custom.on_enter : ""; |
569 | 0 | default: |
570 | 0 | break; |
571 | 0 | } |
572 | | |
573 | 0 | return NULL; |
574 | 0 | } |
575 | | |
576 | 0 | int cmark_node_set_on_enter(cmark_node *node, const char *on_enter) { |
577 | 0 | if (node == NULL) { |
578 | 0 | return 0; |
579 | 0 | } |
580 | | |
581 | 0 | switch (node->type) { |
582 | 0 | case CMARK_NODE_CUSTOM_INLINE: |
583 | 0 | case CMARK_NODE_CUSTOM_BLOCK: |
584 | 0 | cmark_set_cstr(node->mem, &node->as.custom.on_enter, on_enter); |
585 | 0 | return 1; |
586 | 0 | default: |
587 | 0 | break; |
588 | 0 | } |
589 | | |
590 | 0 | return 0; |
591 | 0 | } |
592 | | |
593 | 0 | const char *cmark_node_get_on_exit(cmark_node *node) { |
594 | 0 | if (node == NULL) { |
595 | 0 | return NULL; |
596 | 0 | } |
597 | | |
598 | 0 | switch (node->type) { |
599 | 0 | case CMARK_NODE_CUSTOM_INLINE: |
600 | 0 | case CMARK_NODE_CUSTOM_BLOCK: |
601 | 0 | return node->as.custom.on_exit ? (char *)node->as.custom.on_exit : ""; |
602 | 0 | default: |
603 | 0 | break; |
604 | 0 | } |
605 | | |
606 | 0 | return NULL; |
607 | 0 | } |
608 | | |
609 | 0 | int cmark_node_set_on_exit(cmark_node *node, const char *on_exit) { |
610 | 0 | if (node == NULL) { |
611 | 0 | return 0; |
612 | 0 | } |
613 | | |
614 | 0 | switch (node->type) { |
615 | 0 | case CMARK_NODE_CUSTOM_INLINE: |
616 | 0 | case CMARK_NODE_CUSTOM_BLOCK: |
617 | 0 | cmark_set_cstr(node->mem, &node->as.custom.on_exit, on_exit); |
618 | 0 | return 1; |
619 | 0 | default: |
620 | 0 | break; |
621 | 0 | } |
622 | | |
623 | 0 | return 0; |
624 | 0 | } |
625 | | |
626 | 8.06M | int cmark_node_get_start_line(cmark_node *node) { |
627 | 8.06M | if (node == NULL) { |
628 | 0 | return 0; |
629 | 0 | } |
630 | 8.06M | return node->start_line; |
631 | 8.06M | } |
632 | | |
633 | 8.06M | int cmark_node_get_start_column(cmark_node *node) { |
634 | 8.06M | if (node == NULL) { |
635 | 0 | return 0; |
636 | 0 | } |
637 | 8.06M | return node->start_column; |
638 | 8.06M | } |
639 | | |
640 | 8.06M | int cmark_node_get_end_line(cmark_node *node) { |
641 | 8.06M | if (node == NULL) { |
642 | 0 | return 0; |
643 | 0 | } |
644 | 8.06M | return node->end_line; |
645 | 8.06M | } |
646 | | |
647 | 8.06M | int cmark_node_get_end_column(cmark_node *node) { |
648 | 8.06M | if (node == NULL) { |
649 | 0 | return 0; |
650 | 0 | } |
651 | 8.06M | return node->end_column; |
652 | 8.06M | } |
653 | | |
654 | | // Unlink a node without adjusting its next, prev, and parent pointers. |
655 | 51.6M | static void S_node_unlink(cmark_node *node) { |
656 | 51.6M | if (node == NULL) { |
657 | 0 | return; |
658 | 0 | } |
659 | | |
660 | 51.6M | if (node->prev) { |
661 | 51.1M | node->prev->next = node->next; |
662 | 51.1M | } |
663 | 51.6M | if (node->next) { |
664 | 48.7M | node->next->prev = node->prev; |
665 | 48.7M | } |
666 | | |
667 | | // Adjust first_child and last_child of parent. |
668 | 51.6M | cmark_node *parent = node->parent; |
669 | 51.6M | if (parent) { |
670 | 51.1M | if (parent->first_child == node) { |
671 | 8.26k | parent->first_child = node->next; |
672 | 8.26k | } |
673 | 51.1M | if (parent->last_child == node) { |
674 | 2.43M | parent->last_child = node->prev; |
675 | 2.43M | } |
676 | 51.1M | } |
677 | 51.6M | } |
678 | | |
679 | 728k | void cmark_node_unlink(cmark_node *node) { |
680 | 728k | S_node_unlink(node); |
681 | | |
682 | 728k | node->next = NULL; |
683 | 728k | node->prev = NULL; |
684 | 728k | node->parent = NULL; |
685 | 728k | } |
686 | | |
687 | 461k | int cmark_node_insert_before(cmark_node *node, cmark_node *sibling) { |
688 | 461k | if (node == NULL || sibling == NULL) { |
689 | 0 | return 0; |
690 | 0 | } |
691 | | |
692 | 461k | if (!node->parent || !S_can_contain(node->parent, sibling)) { |
693 | 0 | return 0; |
694 | 0 | } |
695 | | |
696 | 461k | S_node_unlink(sibling); |
697 | | |
698 | 461k | cmark_node *old_prev = node->prev; |
699 | | |
700 | | // Insert 'sibling' between 'old_prev' and 'node'. |
701 | 461k | if (old_prev) { |
702 | 430k | old_prev->next = sibling; |
703 | 430k | } |
704 | 461k | sibling->prev = old_prev; |
705 | 461k | sibling->next = node; |
706 | 461k | node->prev = sibling; |
707 | | |
708 | | // Set new parent. |
709 | 461k | cmark_node *parent = node->parent; |
710 | 461k | sibling->parent = parent; |
711 | | |
712 | | // Adjust first_child of parent if inserted as first child. |
713 | 461k | if (parent && !old_prev) { |
714 | 31.4k | parent->first_child = sibling; |
715 | 31.4k | } |
716 | | |
717 | 461k | return 1; |
718 | 461k | } |
719 | | |
720 | 0 | int cmark_node_insert_after(cmark_node *node, cmark_node *sibling) { |
721 | 0 | if (node == NULL || sibling == NULL) { |
722 | 0 | return 0; |
723 | 0 | } |
724 | | |
725 | 0 | if (!node->parent || !S_can_contain(node->parent, sibling)) { |
726 | 0 | return 0; |
727 | 0 | } |
728 | | |
729 | 0 | S_node_unlink(sibling); |
730 | |
|
731 | 0 | cmark_node *old_next = node->next; |
732 | | |
733 | | // Insert 'sibling' between 'node' and 'old_next'. |
734 | 0 | if (old_next) { |
735 | 0 | old_next->prev = sibling; |
736 | 0 | } |
737 | 0 | sibling->next = old_next; |
738 | 0 | sibling->prev = node; |
739 | 0 | node->next = sibling; |
740 | | |
741 | | // Set new parent. |
742 | 0 | cmark_node *parent = node->parent; |
743 | 0 | sibling->parent = parent; |
744 | | |
745 | | // Adjust last_child of parent if inserted as last child. |
746 | 0 | if (parent && !old_next) { |
747 | 0 | parent->last_child = sibling; |
748 | 0 | } |
749 | |
|
750 | 0 | return 1; |
751 | 0 | } |
752 | | |
753 | 0 | int cmark_node_replace(cmark_node *oldnode, cmark_node *newnode) { |
754 | 0 | if (!cmark_node_insert_before(oldnode, newnode)) { |
755 | 0 | return 0; |
756 | 0 | } |
757 | 0 | cmark_node_unlink(oldnode); |
758 | 0 | return 1; |
759 | 0 | } |
760 | | |
761 | 0 | int cmark_node_prepend_child(cmark_node *node, cmark_node *child) { |
762 | 0 | if (!S_can_contain(node, child)) { |
763 | 0 | return 0; |
764 | 0 | } |
765 | | |
766 | 0 | S_node_unlink(child); |
767 | |
|
768 | 0 | cmark_node *old_first_child = node->first_child; |
769 | |
|
770 | 0 | child->next = old_first_child; |
771 | 0 | child->prev = NULL; |
772 | 0 | child->parent = node; |
773 | 0 | node->first_child = child; |
774 | |
|
775 | 0 | if (old_first_child) { |
776 | 0 | old_first_child->prev = child; |
777 | 0 | } else { |
778 | | // Also set last_child if node previously had no children. |
779 | 0 | node->last_child = child; |
780 | 0 | } |
781 | |
|
782 | 0 | return 1; |
783 | 0 | } |
784 | | |
785 | 0 | int cmark_node_append_child(cmark_node *node, cmark_node *child) { |
786 | 0 | if (!S_can_contain(node, child)) { |
787 | 0 | return 0; |
788 | 0 | } |
789 | | |
790 | 0 | S_node_unlink(child); |
791 | |
|
792 | 0 | cmark_node *old_last_child = node->last_child; |
793 | |
|
794 | 0 | child->next = NULL; |
795 | 0 | child->prev = old_last_child; |
796 | 0 | child->parent = node; |
797 | 0 | node->last_child = child; |
798 | |
|
799 | 0 | if (old_last_child) { |
800 | 0 | old_last_child->next = child; |
801 | 0 | } else { |
802 | | // Also set first_child if node previously had no children. |
803 | 0 | node->first_child = child; |
804 | 0 | } |
805 | |
|
806 | 0 | return 1; |
807 | 0 | } |
808 | | |
809 | 0 | static void S_print_error(FILE *out, cmark_node *node, const char *elem) { |
810 | 0 | if (out == NULL) { |
811 | 0 | return; |
812 | 0 | } |
813 | 0 | fprintf(out, "Invalid '%s' in node type %s at %d:%d\n", elem, |
814 | 0 | cmark_node_get_type_string(node), node->start_line, |
815 | 0 | node->start_column); |
816 | 0 | } |
817 | | |
818 | 0 | int cmark_node_check(cmark_node *node, FILE *out) { |
819 | 0 | cmark_node *cur; |
820 | 0 | int errors = 0; |
821 | |
|
822 | 0 | if (!node) { |
823 | 0 | return 0; |
824 | 0 | } |
825 | | |
826 | 0 | cur = node; |
827 | 0 | for (;;) { |
828 | 0 | if (cur->first_child) { |
829 | 0 | if (cur->first_child->prev != NULL) { |
830 | 0 | S_print_error(out, cur->first_child, "prev"); |
831 | 0 | cur->first_child->prev = NULL; |
832 | 0 | ++errors; |
833 | 0 | } |
834 | 0 | if (cur->first_child->parent != cur) { |
835 | 0 | S_print_error(out, cur->first_child, "parent"); |
836 | 0 | cur->first_child->parent = cur; |
837 | 0 | ++errors; |
838 | 0 | } |
839 | 0 | cur = cur->first_child; |
840 | 0 | continue; |
841 | 0 | } |
842 | | |
843 | 0 | next_sibling: |
844 | 0 | if (cur == node) { |
845 | 0 | break; |
846 | 0 | } |
847 | 0 | if (cur->next) { |
848 | 0 | if (cur->next->prev != cur) { |
849 | 0 | S_print_error(out, cur->next, "prev"); |
850 | 0 | cur->next->prev = cur; |
851 | 0 | ++errors; |
852 | 0 | } |
853 | 0 | if (cur->next->parent != cur->parent) { |
854 | 0 | S_print_error(out, cur->next, "parent"); |
855 | 0 | cur->next->parent = cur->parent; |
856 | 0 | ++errors; |
857 | 0 | } |
858 | 0 | cur = cur->next; |
859 | 0 | continue; |
860 | 0 | } |
861 | | |
862 | 0 | if (cur->parent->last_child != cur) { |
863 | 0 | S_print_error(out, cur->parent, "last_child"); |
864 | 0 | cur->parent->last_child = cur; |
865 | 0 | ++errors; |
866 | 0 | } |
867 | 0 | cur = cur->parent; |
868 | 0 | goto next_sibling; |
869 | 0 | } |
870 | | |
871 | 0 | return errors; |
872 | 0 | } |