cmark
My personal build of CMark ✏️
iterator.c (3518B)
1 #include <assert.h> 2 #include <stdlib.h> 3 4 #include "config.h" 5 #include "node.h" 6 #include "cmark.h" 7 #include "iterator.h" 8 9 static const int S_leaf_mask = 10 (1 << CMARK_NODE_HTML_BLOCK) | (1 << CMARK_NODE_THEMATIC_BREAK) | 11 (1 << CMARK_NODE_CODE_BLOCK) | (1 << CMARK_NODE_TEXT) | 12 (1 << CMARK_NODE_SOFTBREAK) | (1 << CMARK_NODE_LINEBREAK) | 13 (1 << CMARK_NODE_CODE) | (1 << CMARK_NODE_HTML_INLINE); 14 15 cmark_iter *cmark_iter_new(cmark_node *root) { 16 if (root == NULL) { 17 return NULL; 18 } 19 cmark_mem *mem = root->mem; 20 cmark_iter *iter = (cmark_iter *)mem->calloc(1, sizeof(cmark_iter)); 21 iter->mem = mem; 22 iter->root = root; 23 iter->cur.ev_type = CMARK_EVENT_NONE; 24 iter->cur.node = NULL; 25 iter->next.ev_type = CMARK_EVENT_ENTER; 26 iter->next.node = root; 27 return iter; 28 } 29 30 void cmark_iter_free(cmark_iter *iter) { iter->mem->free(iter); } 31 32 static bool S_is_leaf(cmark_node *node) { 33 return ((1 << node->type) & S_leaf_mask) != 0; 34 } 35 36 cmark_event_type cmark_iter_next(cmark_iter *iter) { 37 cmark_event_type ev_type = iter->next.ev_type; 38 cmark_node *node = iter->next.node; 39 40 iter->cur.ev_type = ev_type; 41 iter->cur.node = node; 42 43 if (ev_type == CMARK_EVENT_DONE) { 44 return ev_type; 45 } 46 47 /* roll forward to next item, setting both fields */ 48 if (ev_type == CMARK_EVENT_ENTER && !S_is_leaf(node)) { 49 if (node->first_child == NULL) { 50 /* stay on this node but exit */ 51 iter->next.ev_type = CMARK_EVENT_EXIT; 52 } else { 53 iter->next.ev_type = CMARK_EVENT_ENTER; 54 iter->next.node = node->first_child; 55 } 56 } else if (node == iter->root) { 57 /* don't move past root */ 58 iter->next.ev_type = CMARK_EVENT_DONE; 59 iter->next.node = NULL; 60 } else if (node->next) { 61 iter->next.ev_type = CMARK_EVENT_ENTER; 62 iter->next.node = node->next; 63 } else if (node->parent) { 64 iter->next.ev_type = CMARK_EVENT_EXIT; 65 iter->next.node = node->parent; 66 } else { 67 assert(false); 68 iter->next.ev_type = CMARK_EVENT_DONE; 69 iter->next.node = NULL; 70 } 71 72 return ev_type; 73 } 74 75 void cmark_iter_reset(cmark_iter *iter, cmark_node *current, 76 cmark_event_type event_type) { 77 iter->next.ev_type = event_type; 78 iter->next.node = current; 79 cmark_iter_next(iter); 80 } 81 82 cmark_node *cmark_iter_get_node(cmark_iter *iter) { return iter->cur.node; } 83 84 cmark_event_type cmark_iter_get_event_type(cmark_iter *iter) { 85 return iter->cur.ev_type; 86 } 87 88 cmark_node *cmark_iter_get_root(cmark_iter *iter) { return iter->root; } 89 90 void cmark_consolidate_text_nodes(cmark_node *root) { 91 if (root == NULL) { 92 return; 93 } 94 cmark_iter *iter = cmark_iter_new(root); 95 cmark_strbuf buf = CMARK_BUF_INIT(iter->mem); 96 cmark_event_type ev_type; 97 cmark_node *cur, *tmp, *next; 98 99 while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { 100 cur = cmark_iter_get_node(iter); 101 if (ev_type == CMARK_EVENT_ENTER && cur->type == CMARK_NODE_TEXT && 102 cur->next && cur->next->type == CMARK_NODE_TEXT) { 103 cmark_strbuf_clear(&buf); 104 cmark_strbuf_put(&buf, cur->data, cur->len); 105 tmp = cur->next; 106 while (tmp && tmp->type == CMARK_NODE_TEXT) { 107 cmark_iter_next(iter); // advance pointer 108 cmark_strbuf_put(&buf, tmp->data, tmp->len); 109 cur->end_column = tmp->end_column; 110 next = tmp->next; 111 cmark_node_free(tmp); 112 tmp = next; 113 } 114 iter->mem->free(cur->data); 115 cur->len = buf.size; 116 cur->data = cmark_strbuf_detach(&buf); 117 } 118 } 119 120 cmark_strbuf_free(&buf); 121 cmark_iter_free(iter); 122 }