diff options
Diffstat (limited to 'src/node.c')
-rw-r--r-- | src/node.c | 1585 |
1 files changed, 746 insertions, 839 deletions
@@ -4,855 +4,762 @@ #include "config.h" #include "node.h" -static void -S_node_unlink(cmark_node *node); - -static inline bool -S_is_block(cmark_node *node) -{ - if (node == NULL) { - return false; - } - return node->type >= CMARK_NODE_FIRST_BLOCK - && node->type <= CMARK_NODE_LAST_BLOCK; -} - -static inline bool -S_is_inline(cmark_node *node) -{ - if (node == NULL) { - return false; - } - return node->type >= CMARK_NODE_FIRST_INLINE - && node->type <= CMARK_NODE_LAST_INLINE; -} - -static bool -S_can_contain(cmark_node *node, cmark_node *child) -{ - cmark_node *cur; - - if (node == NULL || child == NULL) { - return false; - } - - // Verify that child is not an ancestor of node or equal to node. - cur = node; - do { - if (cur == child) { - return false; - } - cur = cur->parent; - } while (cur != NULL); - - if (child->type == CMARK_NODE_DOCUMENT) { - return false; - } - - switch (node->type) { - case CMARK_NODE_DOCUMENT: - case CMARK_NODE_BLOCK_QUOTE: - case CMARK_NODE_ITEM: - return S_is_block(child) - && child->type != CMARK_NODE_ITEM; - - case CMARK_NODE_LIST: - return child->type == CMARK_NODE_ITEM; - - case CMARK_NODE_PARAGRAPH: - case CMARK_NODE_HEADER: - case CMARK_NODE_EMPH: - case CMARK_NODE_STRONG: - case CMARK_NODE_LINK: - case CMARK_NODE_IMAGE: - return S_is_inline(child); - - default: - break; - } - - return false; -} - -cmark_node* -cmark_node_new(cmark_node_type type) -{ - cmark_node *node = (cmark_node *)calloc(1, sizeof(*node)); - node->type = type; - - switch (node->type) { - case CMARK_NODE_HEADER: - node->as.header.level = 1; - break; - - case CMARK_NODE_LIST: { - cmark_list *list = &node->as.list; - list->list_type = CMARK_BULLET_LIST; - list->start = 1; - list->tight = false; - break; - } - - default: - break; - } - - return node; +static void S_node_unlink(cmark_node *node); + +static inline bool S_is_block(cmark_node *node) { + if (node == NULL) { + return false; + } + return node->type >= CMARK_NODE_FIRST_BLOCK && + node->type <= CMARK_NODE_LAST_BLOCK; +} + +static inline bool S_is_inline(cmark_node *node) { + if (node == NULL) { + return false; + } + return node->type >= CMARK_NODE_FIRST_INLINE && + node->type <= CMARK_NODE_LAST_INLINE; +} + +static bool S_can_contain(cmark_node *node, cmark_node *child) { + cmark_node *cur; + + if (node == NULL || child == NULL) { + return false; + } + + // Verify that child is not an ancestor of node or equal to node. + cur = node; + do { + if (cur == child) { + return false; + } + cur = cur->parent; + } while (cur != NULL); + + if (child->type == CMARK_NODE_DOCUMENT) { + return false; + } + + switch (node->type) { + case CMARK_NODE_DOCUMENT: + case CMARK_NODE_BLOCK_QUOTE: + case CMARK_NODE_ITEM: + return S_is_block(child) && child->type != CMARK_NODE_ITEM; + + case CMARK_NODE_LIST: + return child->type == CMARK_NODE_ITEM; + + case CMARK_NODE_PARAGRAPH: + case CMARK_NODE_HEADER: + case CMARK_NODE_EMPH: + case CMARK_NODE_STRONG: + case CMARK_NODE_LINK: + case CMARK_NODE_IMAGE: + return S_is_inline(child); + + default: + break; + } + + return false; +} + +cmark_node *cmark_node_new(cmark_node_type type) { + cmark_node *node = (cmark_node *)calloc(1, sizeof(*node)); + node->type = type; + + switch (node->type) { + case CMARK_NODE_HEADER: + node->as.header.level = 1; + break; + + case CMARK_NODE_LIST: { + cmark_list *list = &node->as.list; + list->list_type = CMARK_BULLET_LIST; + list->start = 1; + list->tight = false; + break; + } + + default: + break; + } + + return node; } // Free a cmark_node list and any children. -static -void S_free_nodes(cmark_node *e) -{ - cmark_node *next; - while (e != NULL) { - if (S_is_block(e)) { - cmark_strbuf_free(&e->string_content); - } - switch (e->type) { - case NODE_CODE_BLOCK: - cmark_chunk_free(&e->as.code.info); - cmark_chunk_free(&e->as.code.literal); - break; - case NODE_TEXT: - case NODE_INLINE_HTML: - case NODE_CODE: - case NODE_HTML: - cmark_chunk_free(&e->as.literal); - break; - case NODE_LINK: - case NODE_IMAGE: - cmark_chunk_free(&e->as.link.url); - cmark_chunk_free(&e->as.link.title); - break; - default: - break; - } - if (e->last_child) { - // Splice children into list - e->last_child->next = e->next; - e->next = e->first_child; - } - next = e->next; - free(e); - e = next; - } -} - -void -cmark_node_free(cmark_node *node) -{ - S_node_unlink(node); - node->next = NULL; - S_free_nodes(node); -} - -cmark_node_type -cmark_node_get_type(cmark_node *node) -{ - if (node == NULL) { - return CMARK_NODE_NONE; - } else { - return node->type; - } -} - -const char* -cmark_node_get_type_string(cmark_node *node) -{ - if (node == NULL) { - return "NONE"; - } - - switch (node->type) { - case CMARK_NODE_NONE: - return "none"; - case CMARK_NODE_DOCUMENT: - return "document"; - case CMARK_NODE_BLOCK_QUOTE: - return "block_quote"; - case CMARK_NODE_LIST: - return "list"; - case CMARK_NODE_ITEM: - return "item"; - case CMARK_NODE_CODE_BLOCK: - return "code_block"; - case CMARK_NODE_HTML: - return "html"; - case CMARK_NODE_PARAGRAPH: - return "paragraph"; - case CMARK_NODE_HEADER: - return "header"; - case CMARK_NODE_HRULE: - return "hrule"; - case CMARK_NODE_TEXT: - return "text"; - case CMARK_NODE_SOFTBREAK: - return "softbreak"; - case CMARK_NODE_LINEBREAK: - return "linebreak"; - case CMARK_NODE_CODE: - return "code"; - case CMARK_NODE_INLINE_HTML: - return "inline_html"; - case CMARK_NODE_EMPH: - return "emph"; - case CMARK_NODE_STRONG: - return "strong"; - case CMARK_NODE_LINK: - return "link"; - case CMARK_NODE_IMAGE: - return "image"; - } - - return "<unknown>"; -} - -cmark_node* -cmark_node_next(cmark_node *node) -{ - if (node == NULL) { - return NULL; - } else { - return node->next; - } -} - -cmark_node* -cmark_node_previous(cmark_node *node) -{ - if (node == NULL) { - return NULL; - } else { - return node->prev; - } -} - -cmark_node* -cmark_node_parent(cmark_node *node) -{ - if (node == NULL) { - return NULL; - } else { - return node->parent; - } -} - -cmark_node* -cmark_node_first_child(cmark_node *node) -{ - if (node == NULL) { - return NULL; - } else { - return node->first_child; - } -} - -cmark_node* -cmark_node_last_child(cmark_node *node) -{ - if (node == NULL) { - return NULL; - } else { - return node->last_child; - } -} - -void* -cmark_node_get_user_data(cmark_node *node) -{ - if (node == NULL) { - return NULL; - } else { - return node->user_data; - } -} - -int -cmark_node_set_user_data(cmark_node *node, void *user_data) -{ - if (node == NULL) { - return 0; - } - node->user_data = user_data; - return 1; -} - -const char* -cmark_node_get_literal(cmark_node *node) -{ - if (node == NULL) { - return NULL; - } - - switch (node->type) { - case NODE_HTML: - case NODE_TEXT: - case NODE_INLINE_HTML: - case NODE_CODE: - return cmark_chunk_to_cstr(&node->as.literal); - - case NODE_CODE_BLOCK: - return cmark_chunk_to_cstr(&node->as.code.literal); - - default: - break; - } - - return NULL; -} - -int -cmark_node_set_literal(cmark_node *node, const char *content) -{ - if (node == NULL) { - return 0; - } - - switch (node->type) { - case NODE_HTML: - case NODE_TEXT: - case NODE_INLINE_HTML: - case NODE_CODE: - cmark_chunk_set_cstr(&node->as.literal, content); - return 1; - - case NODE_CODE_BLOCK: - cmark_chunk_set_cstr(&node->as.code.literal, content); - return 1; - - default: - break; - } - - return 0; -} - -int -cmark_node_get_header_level(cmark_node *node) -{ - if (node == NULL) { - return 0; - } - - switch (node->type) { - case CMARK_NODE_HEADER: - return node->as.header.level; - - default: - break; - } - - return 0; -} - -int -cmark_node_set_header_level(cmark_node *node, int level) -{ - if (node == NULL || level < 1 || level > 6) { - return 0; - } - - switch (node->type) { - case CMARK_NODE_HEADER: - node->as.header.level = level; - return 1; - - default: - break; - } - - return 0; -} - -cmark_list_type -cmark_node_get_list_type(cmark_node *node) -{ - if (node == NULL) { - return CMARK_NO_LIST; - } - - if (node->type == CMARK_NODE_LIST) { - return node->as.list.list_type; - } else { - return CMARK_NO_LIST; - } -} - -int -cmark_node_set_list_type(cmark_node *node, cmark_list_type type) -{ - if (!(type == CMARK_BULLET_LIST || type == CMARK_ORDERED_LIST)) { - return 0; - } - - if (node == NULL) { - return 0; - } - - if (node->type == CMARK_NODE_LIST) { - node->as.list.list_type = type; - return 1; - } else { - return 0; - } -} - -cmark_delim_type -cmark_node_get_list_delim(cmark_node *node) -{ - if (node == NULL) { - return CMARK_NO_DELIM; - } - - if (node->type == CMARK_NODE_LIST) { - return node->as.list.delimiter; - } else { - return CMARK_NO_DELIM; - } -} - -int -cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim) -{ - if (!(delim == CMARK_PERIOD_DELIM || delim == CMARK_PAREN_DELIM)) { - return 0; - } - - if (node == NULL) { - return 0; - } - - if (node->type == CMARK_NODE_LIST) { - node->as.list.delimiter = delim; - return 1; - } else { - return 0; - } -} - -int -cmark_node_get_list_start(cmark_node *node) -{ - if (node == NULL) { - return 0; - } - - if (node->type == CMARK_NODE_LIST) { - return node->as.list.start; - } else { - return 0; - } -} - -int -cmark_node_set_list_start(cmark_node *node, int start) -{ - if (node == NULL || start < 0) { - return 0; - } - - if (node->type == CMARK_NODE_LIST) { - node->as.list.start = start; - return 1; - } else { - return 0; - } -} - -int -cmark_node_get_list_tight(cmark_node *node) -{ - if (node == NULL) { - return 0; - } - - if (node->type == CMARK_NODE_LIST) { - return node->as.list.tight; - } else { - return 0; - } -} - -int -cmark_node_set_list_tight(cmark_node *node, int tight) -{ - if (node == NULL) { - return 0; - } - - if (node->type == CMARK_NODE_LIST) { - node->as.list.tight = tight; - return 1; - } else { - return 0; - } -} - -const char* -cmark_node_get_fence_info(cmark_node *node) -{ - if (node == NULL) { - return NULL; - } - - if (node->type == NODE_CODE_BLOCK) { - return cmark_chunk_to_cstr(&node->as.code.info); - } else { - return NULL; - } -} - -int -cmark_node_set_fence_info(cmark_node *node, const char *info) -{ - if (node == NULL) { - return 0; - } - - if (node->type == NODE_CODE_BLOCK) { - cmark_chunk_set_cstr(&node->as.code.info, info); - return 1; - } else { - return 0; - } -} - -const char* -cmark_node_get_url(cmark_node *node) -{ - if (node == NULL) { - return NULL; - } - - switch (node->type) { - case NODE_LINK: - case NODE_IMAGE: - return cmark_chunk_to_cstr(&node->as.link.url); - default: - break; - } - - return NULL; -} - -int -cmark_node_set_url(cmark_node *node, const char *url) -{ - if (node == NULL) { - return 0; - } - - switch (node->type) { - case NODE_LINK: - case NODE_IMAGE: - cmark_chunk_set_cstr(&node->as.link.url, url); - return 1; - default: - break; - } - - return 0; -} - -const char* -cmark_node_get_title(cmark_node *node) -{ - if (node == NULL) { - return NULL; - } - - switch (node->type) { - case NODE_LINK: - case NODE_IMAGE: - return cmark_chunk_to_cstr(&node->as.link.title); - default: - break; - } - - return NULL; -} - -int -cmark_node_set_title(cmark_node *node, const char *title) -{ - if (node == NULL) { - return 0; - } - - switch (node->type) { - case NODE_LINK: - case NODE_IMAGE: - cmark_chunk_set_cstr(&node->as.link.title, title); - return 1; - default: - break; - } - - return 0; -} - -int -cmark_node_get_start_line(cmark_node *node) -{ - if (node == NULL) { - return 0; - } - return node->start_line; -} - -int -cmark_node_get_start_column(cmark_node *node) -{ - if (node == NULL) { - return 0; - } - return node->start_column; -} - -int -cmark_node_get_end_line(cmark_node *node) -{ - if (node == NULL) { - return 0; - } - return node->end_line; -} - -int -cmark_node_get_end_column(cmark_node *node) -{ - if (node == NULL) { - return 0; - } - return node->end_column; +static void S_free_nodes(cmark_node *e) { + cmark_node *next; + while (e != NULL) { + if (S_is_block(e)) { + cmark_strbuf_free(&e->string_content); + } + switch (e->type) { + case NODE_CODE_BLOCK: + cmark_chunk_free(&e->as.code.info); + cmark_chunk_free(&e->as.code.literal); + break; + case NODE_TEXT: + case NODE_INLINE_HTML: + case NODE_CODE: + case NODE_HTML: + cmark_chunk_free(&e->as.literal); + break; + case NODE_LINK: + case NODE_IMAGE: + cmark_chunk_free(&e->as.link.url); + cmark_chunk_free(&e->as.link.title); + break; + default: + break; + } + if (e->last_child) { + // Splice children into list + e->last_child->next = e->next; + e->next = e->first_child; + } + next = e->next; + free(e); + e = next; + } +} + +void cmark_node_free(cmark_node *node) { + S_node_unlink(node); + node->next = NULL; + S_free_nodes(node); +} + +cmark_node_type cmark_node_get_type(cmark_node *node) { + if (node == NULL) { + return CMARK_NODE_NONE; + } else { + return node->type; + } +} + +const char *cmark_node_get_type_string(cmark_node *node) { + if (node == NULL) { + return "NONE"; + } + + switch (node->type) { + case CMARK_NODE_NONE: + return "none"; + case CMARK_NODE_DOCUMENT: + return "document"; + case CMARK_NODE_BLOCK_QUOTE: + return "block_quote"; + case CMARK_NODE_LIST: + return "list"; + case CMARK_NODE_ITEM: + return "item"; + case CMARK_NODE_CODE_BLOCK: + return "code_block"; + case CMARK_NODE_HTML: + return "html"; + case CMARK_NODE_PARAGRAPH: + return "paragraph"; + case CMARK_NODE_HEADER: + return "header"; + case CMARK_NODE_HRULE: + return "hrule"; + case CMARK_NODE_TEXT: + return "text"; + case CMARK_NODE_SOFTBREAK: + return "softbreak"; + case CMARK_NODE_LINEBREAK: + return "linebreak"; + case CMARK_NODE_CODE: + return "code"; + case CMARK_NODE_INLINE_HTML: + return "inline_html"; + case CMARK_NODE_EMPH: + return "emph"; + case CMARK_NODE_STRONG: + return "strong"; + case CMARK_NODE_LINK: + return "link"; + case CMARK_NODE_IMAGE: + return "image"; + } + + return "<unknown>"; +} + +cmark_node *cmark_node_next(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->next; + } +} + +cmark_node *cmark_node_previous(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->prev; + } +} + +cmark_node *cmark_node_parent(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->parent; + } +} + +cmark_node *cmark_node_first_child(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->first_child; + } +} + +cmark_node *cmark_node_last_child(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->last_child; + } +} + +void *cmark_node_get_user_data(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->user_data; + } +} + +int cmark_node_set_user_data(cmark_node *node, void *user_data) { + if (node == NULL) { + return 0; + } + node->user_data = user_data; + return 1; +} + +const char *cmark_node_get_literal(cmark_node *node) { + if (node == NULL) { + return NULL; + } + + switch (node->type) { + case NODE_HTML: + case NODE_TEXT: + case NODE_INLINE_HTML: + case NODE_CODE: + return cmark_chunk_to_cstr(&node->as.literal); + + case NODE_CODE_BLOCK: + return cmark_chunk_to_cstr(&node->as.code.literal); + + default: + break; + } + + return NULL; +} + +int cmark_node_set_literal(cmark_node *node, const char *content) { + if (node == NULL) { + return 0; + } + + switch (node->type) { + case NODE_HTML: + case NODE_TEXT: + case NODE_INLINE_HTML: + case NODE_CODE: + cmark_chunk_set_cstr(&node->as.literal, content); + return 1; + + case NODE_CODE_BLOCK: + cmark_chunk_set_cstr(&node->as.code.literal, content); + return 1; + + default: + break; + } + + return 0; +} + +int cmark_node_get_header_level(cmark_node *node) { + if (node == NULL) { + return 0; + } + + switch (node->type) { + case CMARK_NODE_HEADER: + return node->as.header.level; + + default: + break; + } + + return 0; +} + +int cmark_node_set_header_level(cmark_node *node, int level) { + if (node == NULL || level < 1 || level > 6) { + return 0; + } + + switch (node->type) { + case CMARK_NODE_HEADER: + node->as.header.level = level; + return 1; + + default: + break; + } + + return 0; +} + +cmark_list_type cmark_node_get_list_type(cmark_node *node) { + if (node == NULL) { + return CMARK_NO_LIST; + } + + if (node->type == CMARK_NODE_LIST) { + return node->as.list.list_type; + } else { + return CMARK_NO_LIST; + } +} + +int cmark_node_set_list_type(cmark_node *node, cmark_list_type type) { + if (!(type == CMARK_BULLET_LIST || type == CMARK_ORDERED_LIST)) { + return 0; + } + + if (node == NULL) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + node->as.list.list_type = type; + return 1; + } else { + return 0; + } +} + +cmark_delim_type cmark_node_get_list_delim(cmark_node *node) { + if (node == NULL) { + return CMARK_NO_DELIM; + } + + if (node->type == CMARK_NODE_LIST) { + return node->as.list.delimiter; + } else { + return CMARK_NO_DELIM; + } +} + +int cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim) { + if (!(delim == CMARK_PERIOD_DELIM || delim == CMARK_PAREN_DELIM)) { + return 0; + } + + if (node == NULL) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + node->as.list.delimiter = delim; + return 1; + } else { + return 0; + } +} + +int cmark_node_get_list_start(cmark_node *node) { + if (node == NULL) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + return node->as.list.start; + } else { + return 0; + } +} + +int cmark_node_set_list_start(cmark_node *node, int start) { + if (node == NULL || start < 0) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + node->as.list.start = start; + return 1; + } else { + return 0; + } +} + +int cmark_node_get_list_tight(cmark_node *node) { + if (node == NULL) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + return node->as.list.tight; + } else { + return 0; + } +} + +int cmark_node_set_list_tight(cmark_node *node, int tight) { + if (node == NULL) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + node->as.list.tight = tight; + return 1; + } else { + return 0; + } +} + +const char *cmark_node_get_fence_info(cmark_node *node) { + if (node == NULL) { + return NULL; + } + + if (node->type == NODE_CODE_BLOCK) { + return cmark_chunk_to_cstr(&node->as.code.info); + } else { + return NULL; + } +} + +int cmark_node_set_fence_info(cmark_node *node, const char *info) { + if (node == NULL) { + return 0; + } + + if (node->type == NODE_CODE_BLOCK) { + cmark_chunk_set_cstr(&node->as.code.info, info); + return 1; + } else { + return 0; + } +} + +const char *cmark_node_get_url(cmark_node *node) { + if (node == NULL) { + return NULL; + } + + switch (node->type) { + case NODE_LINK: + case NODE_IMAGE: + return cmark_chunk_to_cstr(&node->as.link.url); + default: + break; + } + + return NULL; +} + +int cmark_node_set_url(cmark_node *node, const char *url) { + if (node == NULL) { + return 0; + } + + switch (node->type) { + case NODE_LINK: + case NODE_IMAGE: + cmark_chunk_set_cstr(&node->as.link.url, url); + return 1; + default: + break; + } + + return 0; +} + +const char *cmark_node_get_title(cmark_node *node) { + if (node == NULL) { + return NULL; + } + + switch (node->type) { + case NODE_LINK: + case NODE_IMAGE: + return cmark_chunk_to_cstr(&node->as.link.title); + default: + break; + } + + return NULL; +} + +int cmark_node_set_title(cmark_node *node, const char *title) { + if (node == NULL) { + return 0; + } + + switch (node->type) { + case NODE_LINK: + case NODE_IMAGE: + cmark_chunk_set_cstr(&node->as.link.title, title); + return 1; + default: + break; + } + + return 0; +} + +int cmark_node_get_start_line(cmark_node *node) { + if (node == NULL) { + return 0; + } + return node->start_line; +} + +int cmark_node_get_start_column(cmark_node *node) { + if (node == NULL) { + return 0; + } + return node->start_column; +} + +int cmark_node_get_end_line(cmark_node *node) { + if (node == NULL) { + return 0; + } + return node->end_line; +} + +int cmark_node_get_end_column(cmark_node *node) { + if (node == NULL) { + return 0; + } + return node->end_column; } // Unlink a node without adjusting its next, prev, and parent pointers. -static void -S_node_unlink(cmark_node *node) -{ - if (node == NULL) { - return; - } +static void S_node_unlink(cmark_node *node) { + if (node == NULL) { + return; + } - if (node->prev) { - node->prev->next = node->next; - } - if (node->next) { - node->next->prev = node->prev; - } - - // Adjust first_child and last_child of parent. - cmark_node *parent = node->parent; - if (parent) { - if (parent->first_child == node) { - parent->first_child = node->next; - } - if (parent->last_child == node) { - parent->last_child = node->prev; - } - } -} - -void -cmark_node_unlink(cmark_node *node) -{ - S_node_unlink(node); - - node->next = NULL; - node->prev = NULL; - node->parent = NULL; + if (node->prev) { + node->prev->next = node->next; + } + if (node->next) { + node->next->prev = node->prev; + } -} - -int -cmark_node_insert_before(cmark_node *node, cmark_node *sibling) -{ - if (node == NULL || sibling == NULL) { - return 0; - } + // Adjust first_child and last_child of parent. + cmark_node *parent = node->parent; + if (parent) { + if (parent->first_child == node) { + parent->first_child = node->next; + } + if (parent->last_child == node) { + parent->last_child = node->prev; + } + } +} - if (!node->parent || !S_can_contain(node->parent, sibling)) { - return 0; - } - - S_node_unlink(sibling); +void cmark_node_unlink(cmark_node *node) { + S_node_unlink(node); - cmark_node *old_prev = node->prev; - - // Insert 'sibling' between 'old_prev' and 'node'. - if (old_prev) { - old_prev->next = sibling; - } - sibling->prev = old_prev; - sibling->next = node; - node->prev = sibling; + node->next = NULL; + node->prev = NULL; + node->parent = NULL; +} + +int cmark_node_insert_before(cmark_node *node, cmark_node *sibling) { + if (node == NULL || sibling == NULL) { + return 0; + } + + if (!node->parent || !S_can_contain(node->parent, sibling)) { + return 0; + } + + S_node_unlink(sibling); + + cmark_node *old_prev = node->prev; + + // Insert 'sibling' between 'old_prev' and 'node'. + if (old_prev) { + old_prev->next = sibling; + } + sibling->prev = old_prev; + sibling->next = node; + node->prev = sibling; - // Set new parent. - cmark_node *parent = node->parent; - sibling->parent = parent; - - // Adjust first_child of parent if inserted as first child. - if (parent && !old_prev) { - parent->first_child = sibling; - } - - return 1; + // Set new parent. + cmark_node *parent = node->parent; + sibling->parent = parent; + + // Adjust first_child of parent if inserted as first child. + if (parent && !old_prev) { + parent->first_child = sibling; + } + + return 1; } - -int -cmark_node_insert_after(cmark_node *node, cmark_node *sibling) -{ - if (node == NULL || sibling == NULL) { - return 0; - } - - if (!node->parent || !S_can_contain(node->parent, sibling)) { - return 0; - } - - S_node_unlink(sibling); - - cmark_node *old_next = node->next; - - // Insert 'sibling' between 'node' and 'old_next'. - if (old_next) { - old_next->prev = sibling; - } - sibling->next = old_next; - sibling->prev = node; - node->next = sibling; - - // Set new parent. - cmark_node *parent = node->parent; - sibling->parent = parent; - - // Adjust last_child of parent if inserted as last child. - if (parent && !old_next) { - parent->last_child = sibling; - } - - return 1; -} - -int -cmark_node_prepend_child(cmark_node *node, cmark_node *child) -{ - if (!S_can_contain(node, child)) { - return 0; - } - - S_node_unlink(child); - - cmark_node *old_first_child = node->first_child; - - child->next = old_first_child; - child->prev = NULL; - child->parent = node; - node->first_child = child; - - if (old_first_child) { - old_first_child->prev = child; - } else { - // Also set last_child if node previously had no children. - node->last_child = child; - } - - return 1; -} - -int -cmark_node_append_child(cmark_node *node, cmark_node *child) -{ - if (!S_can_contain(node, child)) { - return 0; - } - - S_node_unlink(child); - - cmark_node *old_last_child = node->last_child; - - child->next = NULL; - child->prev = old_last_child; - child->parent = node; - node->last_child = child; - - if (old_last_child) { - old_last_child->next = child; - } else { - // Also set first_child if node previously had no children. - node->first_child = child; - } - - return 1; -} - -static void -S_print_error(FILE *out, cmark_node *node, const char *elem) -{ - if (out == NULL) { - return; - } - fprintf(out, "Invalid '%s' in node type %s at %d:%d\n", elem, - cmark_node_get_type_string(node), node->start_line, - node->start_column); -} - -int -cmark_node_check(cmark_node *node, FILE *out) -{ - cmark_node *cur; - int errors = 0; - - if (!node) { - return 0; - } - - cur = node; - while (true) { - if (cur->first_child) { - if (cur->first_child->prev != NULL) { - S_print_error(out, cur->first_child, "prev"); - cur->first_child->prev = NULL; - ++errors; - } - if (cur->first_child->parent != cur) { - S_print_error(out, cur->first_child, "parent"); - cur->first_child->parent = cur; - ++errors; - } - cur = cur->first_child; - continue; - } - -next_sibling: - if (cur == node) { - break; - } - if (cur->next) { - if (cur->next->prev != cur) { - S_print_error(out, cur->next, "prev"); - cur->next->prev = cur; - ++errors; - } - if (cur->next->parent != cur->parent) { - S_print_error(out, cur->next, "parent"); - cur->next->parent = cur->parent; - ++errors; - } - cur = cur->next; - continue; - } - - if (cur->parent->last_child != cur) { - S_print_error(out, cur->parent, "last_child"); - cur->parent->last_child = cur; - ++errors; - } - cur = cur->parent; - goto next_sibling; - } - - return errors; + +int cmark_node_insert_after(cmark_node *node, cmark_node *sibling) { + if (node == NULL || sibling == NULL) { + return 0; + } + + if (!node->parent || !S_can_contain(node->parent, sibling)) { + return 0; + } + + S_node_unlink(sibling); + + cmark_node *old_next = node->next; + + // Insert 'sibling' between 'node' and 'old_next'. + if (old_next) { + old_next->prev = sibling; + } + sibling->next = old_next; + sibling->prev = node; + node->next = sibling; + + // Set new parent. + cmark_node *parent = node->parent; + sibling->parent = parent; + + // Adjust last_child of parent if inserted as last child. + if (parent && !old_next) { + parent->last_child = sibling; + } + + return 1; +} + +int cmark_node_prepend_child(cmark_node *node, cmark_node *child) { + if (!S_can_contain(node, child)) { + return 0; + } + + S_node_unlink(child); + + cmark_node *old_first_child = node->first_child; + + child->next = old_first_child; + child->prev = NULL; + child->parent = node; + node->first_child = child; + + if (old_first_child) { + old_first_child->prev = child; + } else { + // Also set last_child if node previously had no children. + node->last_child = child; + } + + return 1; +} + +int cmark_node_append_child(cmark_node *node, cmark_node *child) { + if (!S_can_contain(node, child)) { + return 0; + } + + S_node_unlink(child); + + cmark_node *old_last_child = node->last_child; + + child->next = NULL; + child->prev = old_last_child; + child->parent = node; + node->last_child = child; + + if (old_last_child) { + old_last_child->next = child; + } else { + // Also set first_child if node previously had no children. + node->first_child = child; + } + + return 1; +} + +static void S_print_error(FILE *out, cmark_node *node, const char *elem) { + if (out == NULL) { + return; + } + fprintf(out, "Invalid '%s' in node type %s at %d:%d\n", elem, + cmark_node_get_type_string(node), node->start_line, + node->start_column); +} + +int cmark_node_check(cmark_node *node, FILE *out) { + cmark_node *cur; + int errors = 0; + + if (!node) { + return 0; + } + + cur = node; + while (true) { + if (cur->first_child) { + if (cur->first_child->prev != NULL) { + S_print_error(out, cur->first_child, "prev"); + cur->first_child->prev = NULL; + ++errors; + } + if (cur->first_child->parent != cur) { + S_print_error(out, cur->first_child, "parent"); + cur->first_child->parent = cur; + ++errors; + } + cur = cur->first_child; + continue; + } + + next_sibling: + if (cur == node) { + break; + } + if (cur->next) { + if (cur->next->prev != cur) { + S_print_error(out, cur->next, "prev"); + cur->next->prev = cur; + ++errors; + } + if (cur->next->parent != cur->parent) { + S_print_error(out, cur->next, "parent"); + cur->next->parent = cur->parent; + ++errors; + } + cur = cur->next; + continue; + } + + if (cur->parent->last_child != cur) { + S_print_error(out, cur->parent, "last_child"); + cur->parent->last_child = cur; + ++errors; + } + cur = cur->parent; + goto next_sibling; + } + + return errors; } |