| 149 | } |
| 150 | |
| 151 | char *cmark_render(cmark_node *root, int options, int width, |
| 152 | void (*outc)(cmark_renderer *, cmark_escaping, int32_t, |
| 153 | unsigned char), |
| 154 | int (*render_node)(cmark_renderer *renderer, |
| 155 | cmark_node *node, |
| 156 | cmark_event_type ev_type, int options)) { |
| 157 | cmark_mem *mem = root->mem; |
| 158 | cmark_strbuf pref = CMARK_BUF_INIT(mem); |
| 159 | cmark_strbuf buf = CMARK_BUF_INIT(mem); |
| 160 | cmark_node *cur; |
| 161 | cmark_event_type ev_type; |
| 162 | char *result; |
| 163 | cmark_iter *iter = cmark_iter_new(root); |
| 164 | |
| 165 | cmark_renderer renderer = {options, |
| 166 | mem, &buf, &pref, 0, width, |
| 167 | 0, 0, true, true, false, |
| 168 | false, NULL, |
| 169 | outc, S_cr, S_blankline, S_out}; |
| 170 | |
| 171 | while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { |
| 172 | cur = cmark_iter_get_node(iter); |
| 173 | if (!render_node(&renderer, cur, ev_type, options)) { |
| 174 | // a false value causes us to skip processing |
| 175 | // the node's contents. this is used for |
| 176 | // autolinks. |
| 177 | cmark_iter_reset(iter, cur, CMARK_EVENT_EXIT); |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | // If the root node is a block type (i.e. not inline), ensure there's a final newline: |
| 182 | if (cmark_node_is_block(root)) { |
| 183 | if (renderer.buffer->size == 0 || renderer.buffer->ptr[renderer.buffer->size - 1] != '\n') { |
| 184 | cmark_strbuf_putc(renderer.buffer, '\n'); |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | result = (char *)cmark_strbuf_detach(renderer.buffer); |
| 189 | |
| 190 | cmark_iter_free(iter); |
| 191 | cmark_strbuf_free(renderer.prefix); |
| 192 | cmark_strbuf_free(renderer.buffer); |
| 193 | |
| 194 | return result; |
| 195 | } |
no test coverage detected