Coverage Report

Created: 2026-04-10 06:09

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