cmark

My personal build of CMark ✏️

Commit
4cc37256fdc47faeefe6296cdcce022ec6a60719
Parent
550230aa5575b120782ef307a17317c6827f032e
Author
John MacFarlane <fiddlosopher@gmail.com>
Date

Added cmark_node_handler and cmark_walk to header.

Diffstat

3 files changed, 71 insertions, 1 deletion

Status File Name N° Changes Insertions Deletions
Modified man/man3/cmark.3 6 5 1
Modified src/cmark.h 7 7 0
Modified src/node.c 59 59 0
diff --git 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
@@ -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
@@ -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;
+}