- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include "cmark.h"
- #include "buffer.h"
- #include "node.h"
- #define INDENT 2
- static void print_str(strbuf* buffer, const unsigned char *s, int len)
- {
- int i;
- if (len < 0)
- len = strlen((char *)s);
- strbuf_putc(buffer, '"');
- for (i = 0; i < len; ++i) {
- unsigned char c = s[i];
- switch (c) {
- case '\n':
- strbuf_printf(buffer, "\\n");
- break;
- case '"':
- strbuf_printf(buffer, "\\\"");
- break;
- case '\\':
- strbuf_printf(buffer, "\\\\");
- break;
- default:
- strbuf_putc(buffer, (int)c);
- }
- }
- strbuf_putc(buffer, '"');
- }
- // Prettyprint an inline list, for debugging.
- static void render_nodes(strbuf* buffer, cmark_node* node, int indent)
- {
- int i;
- cmark_list *data;
- while(node != NULL) {
- for (i=0; i < indent; i++) {
- strbuf_putc(buffer, ' ');
- }
- switch(node->type) {
- case NODE_DOCUMENT:
- break;
- case NODE_BLOCK_QUOTE:
- strbuf_printf(buffer, "block_quote\n");
- break;
- case NODE_LIST_ITEM:
- strbuf_printf(buffer, "list_item\n");
- break;
- case NODE_LIST:
- data = &(node->as.list);
- if (data->list_type == CMARK_ORDERED_LIST) {
- strbuf_printf(buffer, "list (type=ordered tight=%s start=%d delim=%s)\n",
- (data->tight ? "true" : "false"),
- data->start,
- (data->delimiter == CMARK_PAREN_DELIM ? "parens" : "period"));
- } else {
- strbuf_printf(buffer, "list (type=bullet tight=%s bullet_char=%c)\n",
- (data->tight ? "true" : "false"),
- data->bullet_char);
- }
- break;
- case NODE_HEADER:
- strbuf_printf(buffer, "header (level=%d)\n", node->as.header.level);
- break;
- case NODE_PARAGRAPH:
- strbuf_printf(buffer, "paragraph\n");
- break;
- case NODE_HRULE:
- strbuf_printf(buffer, "hrule\n");
- break;
- case NODE_CODE_BLOCK:
- strbuf_printf(buffer, "code_block info=");
- print_str(buffer, node->as.code.info.ptr, -1);
- strbuf_putc(buffer, ' ');
- print_str(buffer, node->string_content.ptr, -1);
- strbuf_putc(buffer, '\n');
- break;
- case NODE_HTML:
- strbuf_printf(buffer, "html ");
- print_str(buffer, node->string_content.ptr, -1);
- strbuf_putc(buffer, '\n');
- break;
- case NODE_REFERENCE_DEF:
- // skip
- // strbuf_printf(buffer, "reference_def\n");
- break;
- case NODE_TEXT:
- strbuf_printf(buffer, "text ");
- print_str(buffer, node->as.literal.data, node->as.literal.len);
- strbuf_putc(buffer, '\n');
- break;
- case NODE_LINEBREAK:
- strbuf_printf(buffer, "linebreak\n");
- break;
- case NODE_SOFTBREAK:
- strbuf_printf(buffer, "softbreak\n");
- break;
- case NODE_INLINE_CODE:
- strbuf_printf(buffer, "code ");
- print_str(buffer, node->as.literal.data, node->as.literal.len);
- strbuf_putc(buffer, '\n');
- break;
- case NODE_INLINE_HTML:
- strbuf_printf(buffer, "inline_html ");
- print_str(buffer, node->as.literal.data, node->as.literal.len);
- strbuf_putc(buffer, '\n');
- break;
- case NODE_LINK:
- case NODE_IMAGE:
- strbuf_printf(buffer, "%s url=", node->type == NODE_LINK ? "link" : "image");
- if (node->as.link.url)
- print_str(buffer, node->as.link.url, -1);
- if (node->as.link.title) {
- strbuf_printf(buffer, " title=");
- print_str(buffer, node->as.link.title, -1);
- }
- strbuf_putc(buffer, '\n');
- break;
- case NODE_STRONG:
- strbuf_printf(buffer, "strong\n");
- break;
- case NODE_EMPH:
- strbuf_printf(buffer, "emph\n");
- break;
- default:
- break;
- }
- if (node->first_child) { // render children if any
- indent += INDENT;
- node = node->first_child;
- } else if (node->next) { // otherwise render next sibling
- node = node->next;
- } else {
- node = node->parent; // back up to parent
- while (node) {
- indent -= INDENT;
- if (node->next) {
- node = node->next;
- break;
- } else {
- node = node->parent;
- }
- if (!node) {
- break;
- }
- }
- }
- }
- }
- char *cmark_render_ast(cmark_node *root)
- {
- char* result;
- strbuf buffer = GH_BUF_INIT;
- render_nodes(&buffer, root, -2);
- result = (char *)strbuf_detach(&buffer);
- strbuf_free(&buffer);
- return result;
- }
|