aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmark.h7
-rw-r--r--src/node.c59
2 files changed, 66 insertions, 0 deletions
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.
diff --git a/src/node.c b/src/node.c
index 243c3e6..040aeda 100644
--- a/src/node.c
+++ b/src/node.c
@@ -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;
+}