summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/blocks.c19
-rw-r--r--src/inlines.c32
-rw-r--r--src/node.c58
-rw-r--r--src/node.h3
4 files changed, 107 insertions, 5 deletions
diff --git a/src/blocks.c b/src/blocks.c
index cf5e08c..0e68259 100644
--- a/src/blocks.c
+++ b/src/blocks.c
@@ -283,6 +283,19 @@ typedef struct BlockStack {
cmark_node *next_sibling;
} block_stack;
+static void fix_parents(cmark_node *node) {
+ cmark_node *cur = node->first_child;
+ if (cur == NULL) {
+ return;
+ }
+ while (cur->next != NULL) {
+ cur->parent = node;
+ cur = cur->next;
+ }
+ cur->parent = node;
+ node->last_child = cur;
+}
+
// Walk through cmark_node and all children, recursively, parsing
// string content into inline content where appropriate.
static void process_inlines(cmark_node* cur, reference_map *refmap)
@@ -296,6 +309,7 @@ static void process_inlines(cmark_node* cur, reference_map *refmap)
case NODE_ATX_HEADER:
case NODE_SETEXT_HEADER:
cur->first_child = parse_inlines(&cur->string_content, refmap);
+ fix_parents(cur);
break;
default:
@@ -817,6 +831,11 @@ cmark_node *cmark_finish(cmark_doc_parser *parser)
{
finalize_document(parser);
strbuf_free(parser->curline);
+#if CMARK_DEBUG_NODES
+ if (cmark_node_check(parser->root)) {
+ abort();
+ }
+#endif
return parser->root;
}
diff --git a/src/inlines.c b/src/inlines.c
index 078afd4..96b1792 100644
--- a/src/inlines.c
+++ b/src/inlines.c
@@ -193,6 +193,7 @@ static inline cmark_node* cmark_append_inlines(cmark_node* a, cmark_node* b)
cur = cur->next;
}
cur->next = b;
+ b->prev = cur;
return a;
}
@@ -395,12 +396,8 @@ static void process_emphasis(subject *subj, delimiter_stack *stack_bottom)
// between the opener and closer
emph = use_delims == 1 ? make_emph(inl->next) : make_strong(inl->next);
emph->next = closer->first_inline;
+ emph->prev = inl;
inl->next = emph;
- tmp = emph->first_child;
- while (tmp->next != NULL && tmp->next != closer->first_inline) {
- tmp = tmp->next;
- }
- tmp->next = NULL;
// if opener has 0 delims, remove it and its associated inline
if (opener->delim_count == 0) {
@@ -415,11 +412,27 @@ static void process_emphasis(subject *subj, delimiter_stack *stack_bottom)
remove_delimiter(subj, opener);
}
+ // fix tree structure
+ tmp = emph->first_child;
+ while (tmp->next != NULL && tmp->next != closer->first_inline) {
+ tmp->parent = emph;
+ tmp = tmp->next;
+ }
+ tmp->parent = emph;
+ if (tmp->next) {
+ tmp->next->prev = emph;
+ }
+ tmp->next = NULL;
+ emph->last_child = tmp;
+
// if closer has 0 delims, remove it and its associated inline
if (closer->delim_count == 0) {
// remove empty closer inline
tmp = closer->first_inline;
emph->next = tmp->next;
+ if (tmp->next) {
+ tmp->next->prev = emph;
+ }
tmp->next = NULL;
cmark_free_nodes(tmp);
// remove closer from stack
@@ -727,6 +740,15 @@ match:
inl->as.link.url = url;
inl->as.link.title = title;
inl->next = NULL;
+ if (link_text) {
+ cmark_node *tmp;
+ link_text->prev = NULL;
+ for (tmp = link_text; tmp->next != NULL; tmp = tmp->next) {
+ tmp->parent = inl;
+ }
+ tmp->parent = inl;
+ inl->last_child = tmp;
+ }
*last = inl;
// process_emphasis will remove this delimiter and all later ones.
diff --git a/src/node.c b/src/node.c
index 547382a..ed58e90 100644
--- a/src/node.c
+++ b/src/node.c
@@ -249,6 +249,64 @@ static void splice_into_list(cmark_node* e, cmark_node* children) {
return ;
}
+int
+cmark_node_check(cmark_node *node) {
+ cmark_node *cur = node;
+ int errors = 0;
+
+ while (cur) {
+ if (cur->first_child) {
+ if (cur->first_child->parent != cur) {
+ fprintf(stderr,
+ "Invalid 'parent' in node type %d\n",
+ cur->first_child->type);
+ cur->first_child->parent = cur;
+ ++errors;
+ }
+ cur = cur->first_child;
+ }
+ else if (cur->next) {
+ if (cur->next->prev != cur) {
+ fprintf(stderr,
+ "Invalid 'prev' in node type %d\n",
+ cur->next->type);
+ cur->next->prev = cur;
+ ++errors;
+ }
+ if (cur->next->parent != cur->parent) {
+ fprintf(stderr,
+ "Invalid 'parent' in node type %d\n",
+ cur->next->type);
+ cur->next->parent = cur->parent;
+ ++errors;
+ }
+ cur = cur->next;
+ }
+ else {
+ if (cur->parent->last_child != cur) {
+ fprintf(stderr,
+ "Invalid 'last_child' in node type %d\n",
+ cur->parent->type);
+ cur->parent->last_child = cur;
+ ++errors;
+ }
+
+ cmark_node *ancestor = cur->parent;
+ cur = NULL;
+
+ while (ancestor != node->parent) {
+ if (ancestor->next) {
+ cur = ancestor->next;
+ break;
+ }
+ ancestor = ancestor->parent;
+ }
+ }
+ }
+
+ return errors;
+}
+
// Free a cmark_node list and any children.
void cmark_free_nodes(cmark_node *e)
{
diff --git a/src/node.h b/src/node.h
index 755274e..f57ee3b 100644
--- a/src/node.h
+++ b/src/node.h
@@ -62,6 +62,9 @@ struct cmark_node {
} as;
};
+int
+cmark_node_check(cmark_node *node);
+
#ifdef __cplusplus
}
#endif