summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/man3/cmark.36
-rw-r--r--src/cmark.h7
-rw-r--r--src/node.c59
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.
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;
+}