| 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 | } | 
|---|
| 123 |  | 
|---|