char *cmark_render_xml(cmark_node *root, long options) { char *result; cmark_strbuf xml = GH_BUF_INIT; cmark_event_type ev_type; cmark_node *cur; struct render_state state = { &xml, 0 }; if (options & CMARK_OPT_NORMALIZE) { cmark_consolidate_text_nodes(root); } cmark_iter *iter = cmark_iter_new(root); cmark_strbuf_puts(state.xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); cmark_strbuf_puts(state.xml, "<!DOCTYPE CommonMark SYSTEM \"CommonMark.dtd\">\n"); while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { cur = cmark_iter_get_node(iter); S_render_node(cur, ev_type, &state, options); } result = (char *)cmark_strbuf_detach(&xml); cmark_iter_free(iter); cmark_strbuf_free(&xml); return result; }
void cmark_consolidate_text_nodes(cmark_node *root) { cmark_iter *iter = cmark_iter_new(root); cmark_strbuf buf = GH_BUF_INIT; cmark_event_type ev_type; cmark_node *cur, *tmp, *next; while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { cur = cmark_iter_get_node(iter); if (ev_type == CMARK_EVENT_ENTER && cur->type == CMARK_NODE_TEXT && cur->next && cur->next->type == CMARK_NODE_TEXT) { cmark_strbuf_clear(&buf); cmark_strbuf_puts(&buf, cmark_node_get_literal(cur)); tmp = cur->next; while (tmp && tmp->type == CMARK_NODE_TEXT) { cmark_iter_next(iter); // advance pointer cmark_strbuf_puts(&buf, cmark_node_get_literal(tmp)); next = tmp->next; cmark_node_free(tmp); tmp = next; } cmark_node_set_literal(cur, (char *)cmark_strbuf_detach(&buf)); } } cmark_iter_free(iter); }
char *cmark_render_html_with_mem(cmark_node *root, int options, cmark_llist *extensions, cmark_mem *mem) { char *result; cmark_strbuf html = CMARK_BUF_INIT(mem); cmark_event_type ev_type; cmark_node *cur; cmark_html_renderer renderer = {&html, NULL, NULL, 0, 0, NULL}; cmark_iter *iter = cmark_iter_new(root); for (; extensions; extensions = extensions->next) if (((cmark_syntax_extension *) extensions->data)->html_filter_func) renderer.filter_extensions = cmark_llist_append( mem, renderer.filter_extensions, (cmark_syntax_extension *) extensions->data); while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { cur = cmark_iter_get_node(iter); S_render_node(&renderer, cur, ev_type, options); } if (renderer.footnote_ix) { cmark_strbuf_puts(&html, "</ol>\n</section>\n"); } result = (char *)cmark_strbuf_detach(&html); cmark_llist_free(mem, renderer.filter_extensions); cmark_iter_free(iter); return result; }
static unsigned char *cmark_clean_autolink(cmark_chunk *url, int is_email) { cmark_strbuf buf = GH_BUF_INIT; cmark_chunk_trim(url); if (url->len == 0) return NULL; if (is_email) cmark_strbuf_puts(&buf, "mailto:"); houdini_unescape_html_f(&buf, url->data, url->len); return cmark_strbuf_detach(&buf); }
char* cmark_render(cmark_node *root, int options, int width, void (*outc)(cmark_renderer*, cmark_escaping, int32_t, unsigned char), int (*render_node)(cmark_renderer *renderer, cmark_node *node, cmark_event_type ev_type, int options)) { cmark_strbuf pref = GH_BUF_INIT; cmark_strbuf buf = GH_BUF_INIT; cmark_node *cur; cmark_event_type ev_type; char *result; cmark_iter *iter = cmark_iter_new(root); cmark_renderer renderer = { &buf, &pref, 0, width, 0, 0, true, false, false, outc, S_cr, S_blankline, S_out }; while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { cur = cmark_iter_get_node(iter); if (!render_node(&renderer, cur, ev_type, options)) { // a false value causes us to skip processing // the node's contents. this is used for // autolinks. cmark_iter_reset(iter, cur, CMARK_EVENT_EXIT); } } // ensure final newline if (renderer.buffer->ptr[renderer.buffer->size - 1] != '\n') { cmark_strbuf_putc(renderer.buffer, '\n'); } result = (char *)cmark_strbuf_detach(renderer.buffer); cmark_iter_free(iter); cmark_strbuf_free(renderer.prefix); cmark_strbuf_free(renderer.buffer); return result; }
// Clean a URL: remove surrounding whitespace and surrounding <>, // and remove \ that escape punctuation. unsigned char *cmark_clean_url(cmark_chunk *url) { cmark_strbuf buf = GH_BUF_INIT; cmark_chunk_trim(url); if (url->len == 0) return NULL; if (url->data[0] == '<' && url->data[url->len - 1] == '>') { houdini_unescape_html_f(&buf, url->data + 1, url->len - 2); } else { houdini_unescape_html_f(&buf, url->data, url->len); } cmark_strbuf_unescape(&buf); return cmark_strbuf_detach(&buf); }
char *cmark_render_html(cmark_node *root, int options) { char *result; cmark_strbuf html = GH_BUF_INIT; cmark_event_type ev_type; cmark_node *cur; struct render_state state = { &html, NULL }; cmark_iter *iter = cmark_iter_new(root); while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { cur = cmark_iter_get_node(iter); S_render_node(cur, ev_type, &state, options); } result = (char *)cmark_strbuf_detach(&html); cmark_iter_free(iter); return result; }
char *cmark_render_man(cmark_node *root, long options) { char *result; cmark_strbuf man = GH_BUF_INIT; struct render_state state = { &man, NULL }; cmark_node *cur; cmark_event_type ev_type; cmark_iter *iter = cmark_iter_new(root); if (options == 0) options = 0; // avoid warning about unused parameters while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { cur = cmark_iter_get_node(iter); S_render_node(cur, ev_type, &state); } result = (char *)cmark_strbuf_detach(&man); cmark_iter_free(iter); cmark_strbuf_free(&man); return result; }
unsigned char *cmark_clean_title(cmark_chunk *title) { cmark_strbuf buf = GH_BUF_INIT; unsigned char first, last; if (title->len == 0) return NULL; first = title->data[0]; last = title->data[title->len - 1]; // remove surrounding quotes if any: if ((first == '\'' && last == '\'') || (first == '(' && last == ')') || (first == '"' && last == '"')) { houdini_unescape_html_f(&buf, title->data + 1, title->len - 2); } else { houdini_unescape_html_f(&buf, title->data, title->len); } cmark_strbuf_unescape(&buf); return cmark_strbuf_detach(&buf); }
// normalize reference: collapse internal whitespace to single space, // remove leading/trailing whitespace, case fold // Return NULL if the reference name is actually empty (i.e. composed // solely from whitespace) static unsigned char *normalize_reference(cmark_mem *mem, cmark_chunk *ref) { cmark_strbuf normalized = CMARK_BUF_INIT(mem); unsigned char *result; if (ref == NULL) return NULL; if (ref->len == 0) return NULL; cmark_utf8proc_case_fold(&normalized, ref->data, ref->len); cmark_strbuf_trim(&normalized); cmark_strbuf_normalize_whitespace(&normalized); result = cmark_strbuf_detach(&normalized); assert(result); if (result[0] == '\0') { free(result); return NULL; } return result; }