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