diff options
-rw-r--r-- | man/man3/cmark.3 | 6 | ||||
-rw-r--r-- | src/cmark.h | 7 | ||||
-rw-r--r-- | src/node.c | 59 |
3 files changed, 71 insertions, 1 deletions
diff --git a/man/man3/cmark.3 b/man/man3/cmark.3 index efce745..d2b0cd3 100644 --- a/man/man3/cmark.3 +++ b/man/man3/cmark.3 @@ -1,4 +1,4 @@ -.TH cmark 3 "December 05, 2014" "LOCAL" "Library Functions Manual" +.TH cmark 3 "December 12, 2014" "LOCAL" "Library Functions Manual" .SH NAME .B cmark @@ -272,6 +272,10 @@ typedef enum { .PP +\fIint\fR \fBcmark_walk\fR(\fIcmark_node *root\fR, \fIcmark_node_handler handler\fR, \fIvoid *state\fR) + +.PP + .SH AUTHORS John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer. diff --git a/src/cmark.h b/src/cmark.h index f96cea9..d77749c 100644 --- a/src/cmark.h +++ b/src/cmark.h @@ -86,6 +86,8 @@ typedef enum { typedef struct cmark_node cmark_node; typedef struct cmark_parser cmark_parser; +typedef int (*cmark_node_handler)(cmark_node*, int, void*); + /** * .SH CREATING AND DESTROYING NODES */ @@ -307,6 +309,11 @@ char *cmark_render_ast(cmark_node *root); CMARK_EXPORT char *cmark_render_html(cmark_node *root); +/** + */ +CMARK_EXPORT +int cmark_walk(cmark_node *root, cmark_node_handler handler, void *state); + /** .SH AUTHORS * * John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer. @@ -767,3 +767,62 @@ cmark_node_check(cmark_node *node, FILE *out) return errors; } + +int S_is_leaf_node(cmark_node *current_node) +{ + switch (cmark_node_get_type(current_node)) { + case CMARK_NODE_HTML: + case CMARK_NODE_HRULE: + case CMARK_NODE_REFERENCE_DEF: + case CMARK_NODE_TEXT: + case CMARK_NODE_SOFTBREAK: + case CMARK_NODE_LINEBREAK: + case CMARK_NODE_INLINE_CODE: + case CMARK_NODE_INLINE_HTML: + return 1; + default: + return 0; + } +} + +int cmark_walk(cmark_node *root, cmark_node_handler handler, void *state) +{ + int begin = 1; + cmark_node *current_node = root; + int depth = 0; + cmark_node *next, *parent, *first_child; + + while (current_node != NULL && depth >= 0) { + + next = current_node->next; + parent = current_node->parent; + + if (!handler(current_node, begin, state)) { + return 0; + } + + if (begin && !S_is_leaf_node(current_node)) { + first_child = current_node->first_child; + if (first_child == NULL) { + begin = 0; // stay on this node + } else { + depth += 1; + current_node = first_child; + } + } else { + if (current_node) { + next = current_node->next; + parent = current_node->parent; + } + if (next) { + begin = 1; + current_node = next; + } else { + begin = 0; + depth -= 1; + current_node = parent; + } + } + } + return 1; +} |