diff --git a/api_test/main.c b/api_test/main.c index e23f3c23c..9ad841c4a 100644 --- a/api_test/main.c +++ b/api_test/main.c @@ -73,6 +73,24 @@ static void constructor(test_batch_runner *runner) { } } +static void classifiers(test_batch_runner *runner) { + cmark_node *node = cmark_node_new(CMARK_NODE_BLOCK_QUOTE); + OK(runner, cmark_node_is_block(node), "is block CMARK_NODE_BLOCK_QUOTE"); + OK(runner, !cmark_node_is_inline(node), "is not inline CMARK_NODE_BLOCK_QUOTE"); + OK(runner, !cmark_node_is_leaf(node), "is not leaf CMARK_NODE_BLOCK_QUOTE"); + cmark_node_free(node); + node = cmark_node_new(CMARK_NODE_EMPH); + OK(runner, !cmark_node_is_block(node), "is not block CMARK_NODE_EMPH"); + OK(runner, cmark_node_is_inline(node), "is inline CMARK_NODE_EMPH"); + OK(runner, !cmark_node_is_leaf(node), "is not leaf CMARK_NODE_EMPH"); + cmark_node_free(node); + node = cmark_node_new(CMARK_NODE_THEMATIC_BREAK); + OK(runner, cmark_node_is_block(node), "is block CMARK_NODE_THEMATIC_BREAK"); + OK(runner, !cmark_node_is_inline(node), "is not inline CMARK_NODE_THEMATIC_BREAK"); + OK(runner, cmark_node_is_leaf(node), "is leaf CMARK_NODE_THEMATIC_BREAK"); + cmark_node_free(node); +} + static void accessors(test_batch_runner *runner) { static const char markdown[] = "## Header\n" "\n" @@ -1142,6 +1160,7 @@ int main(void) { version(runner); constructor(runner); + classifiers(runner); accessors(runner); free_parent(runner); node_check(runner); diff --git a/man/man3/cmark.3 b/man/man3/cmark.3 index c0bc2a7d6..e454a510a 100644 --- a/man/man3/cmark.3 +++ b/man/man3/cmark.3 @@ -1,4 +1,4 @@ -.TH cmark 3 "August 03, 2024" "cmark 0.31.1" "Library Functions Manual" +.TH cmark 3 "September 05, 2024" "cmark 0.31.1" "Library Functions Manual" .SH NAME .PP @@ -121,6 +121,28 @@ and allocating a document tree .PP Returns a pointer to the default memory allocator. +.SS +Classifying nodes + +.PP +\fIbool\f[] \fBcmark_node_is_block\f[](\fIcmark_node *node\f[]) + +.PP +Returns true if the node is a block node. */ + +.PP +\fIbool\f[] \fBcmark_node_is_inline\f[](\fIcmark_node *node\f[]) + +.PP +Returns true if the node is an inline node. */ + +.PP +\fIbool\f[] \fBcmark_node_is_leaf\f[](\fIcmark_node *node\f[]) + +.PP +Returns true if the node is a leaf node (a node that cannot contain +children). */ + .SS Creating and Destroying Nodes diff --git a/src/cmark.h b/src/cmark.h index 27e21dce3..6626b0627 100644 --- a/src/cmark.h +++ b/src/cmark.h @@ -2,6 +2,7 @@ #define CMARK_H #include +#include #include #include @@ -104,6 +105,23 @@ typedef struct cmark_mem { */ CMARK_EXPORT cmark_mem *cmark_get_default_mem_allocator(void); +/** + * ## Classifying nodes + */ + +/** Returns true if the node is a block node. + */ +CMARK_EXPORT bool cmark_node_is_block(cmark_node *node); + +/** Returns true if the node is an inline node. + */ +CMARK_EXPORT bool cmark_node_is_inline(cmark_node *node); + +/** Returns true if the node is a leaf node (a node that cannot + contain children). + */ +CMARK_EXPORT bool cmark_node_is_leaf(cmark_node *node); + /** * ## Creating and Destroying Nodes */ diff --git a/src/node.c b/src/node.c index c90b0d41a..c1492545e 100644 --- a/src/node.c +++ b/src/node.c @@ -6,7 +6,7 @@ static void S_node_unlink(cmark_node *node); -static inline bool S_is_block(cmark_node *node) { +bool cmark_node_is_block(cmark_node *node) { if (node == NULL) { return false; } @@ -14,7 +14,7 @@ static inline bool S_is_block(cmark_node *node) { node->type <= CMARK_NODE_LAST_BLOCK; } -static inline bool S_is_inline(cmark_node *node) { +bool cmark_node_is_inline(cmark_node *node) { if (node == NULL) { return false; } @@ -22,6 +22,22 @@ static inline bool S_is_inline(cmark_node *node) { node->type <= CMARK_NODE_LAST_INLINE; } +bool cmark_node_is_leaf(cmark_node *node) { + if (node == NULL) { + return false; + } + switch (node->type) { + case CMARK_NODE_THEMATIC_BREAK: return true; + case CMARK_NODE_CODE_BLOCK : return true; + case CMARK_NODE_TEXT : return true; + case CMARK_NODE_SOFTBREAK : return true; + case CMARK_NODE_LINEBREAK : return true; + case CMARK_NODE_CODE : return true; + case CMARK_NODE_HTML_INLINE: return true; + } + return false; +} + static bool S_can_contain(cmark_node *node, cmark_node *child) { if (node == NULL || child == NULL || node == child) { return false; @@ -47,7 +63,7 @@ static bool S_can_contain(cmark_node *node, cmark_node *child) { case CMARK_NODE_DOCUMENT: case CMARK_NODE_BLOCK_QUOTE: case CMARK_NODE_ITEM: - return S_is_block(child) && child->type != CMARK_NODE_ITEM; + return cmark_node_is_block(child) && child->type != CMARK_NODE_ITEM; case CMARK_NODE_LIST: return child->type == CMARK_NODE_ITEM; @@ -62,7 +78,7 @@ static bool S_can_contain(cmark_node *node, cmark_node *child) { case CMARK_NODE_LINK: case CMARK_NODE_IMAGE: case CMARK_NODE_CUSTOM_INLINE: - return S_is_inline(child); + return cmark_node_is_inline(child); default: break;