Coverage Report

Created: 2024-02-21 06:19

/src/cmark/src/node.c
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
}