Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
/* $Id$ */
/*
* Copyright (c) 2017--2021 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "config.h"
#if HAVE_SYS_QUEUE
# include <sys/queue.h>
#endif
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lowdown.h"
#include "extern.h"
static const char *const names[LOWDOWN__MAX] = {
"LOWDOWN_ROOT", /* LOWDOWN_ROOT */
"LOWDOWN_BLOCKCODE", /* LOWDOWN_BLOCKCODE */
"LOWDOWN_BLOCKQUOTE", /* LOWDOWN_BLOCKQUOTE */
"LOWDOWN_DEFINITION", /* LOWDOWN_DEFINITION */
"LOWDOWN_DEFINITION_TITLE", /* LOWDOWN_DEFINITION_TITLE */
"LOWDOWN_DEFINITION_DATA", /* LOWDOWN_DEFINITION_DATA */
"LOWDOWN_HEADER", /* LOWDOWN_HEADER */
"LOWDOWN_HRULE", /* LOWDOWN_HRULE */
"LOWDOWN_LIST", /* LOWDOWN_LIST */
"LOWDOWN_LISTITEM", /* LOWDOWN_LISTITEM */
"LOWDOWN_PARAGRAPH", /* LOWDOWN_PARAGRAPH */
"LOWDOWN_TABLE_BLOCK", /* LOWDOWN_TABLE_BLOCK */
"LOWDOWN_TABLE_HEADER", /* LOWDOWN_TABLE_HEADER */
"LOWDOWN_TABLE_BODY", /* LOWDOWN_TABLE_BODY */
"LOWDOWN_TABLE_ROW", /* LOWDOWN_TABLE_ROW */
"LOWDOWN_TABLE_CELL", /* LOWDOWN_TABLE_CELL */
"LOWDOWN_BLOCKHTML", /* LOWDOWN_BLOCKHTML */
"LOWDOWN_LINK_AUTO", /* LOWDOWN_LINK_AUTO */
"LOWDOWN_CODESPAN", /* LOWDOWN_CODESPAN */
"LOWDOWN_DOUBLE_EMPHASIS", /* LOWDOWN_DOUBLE_EMPHASIS */
"LOWDOWN_EMPHASIS", /* LOWDOWN_EMPHASIS */
"LOWDOWN_HIGHLIGHT", /* LOWDOWN_HIGHLIGHT */
"LOWDOWN_IMAGE", /* LOWDOWN_IMAGE */
"LOWDOWN_LINEBREAK", /* LOWDOWN_LINEBREAK */
"LOWDOWN_LINK", /* LOWDOWN_LINK */
"LOWDOWN_TRIPLE_EMPHASIS", /* LOWDOWN_TRIPLE_EMPHASIS */
"LOWDOWN_STRIKETHROUGH", /* LOWDOWN_STRIKETHROUGH */
"LOWDOWN_SUPERSCRIPT", /* LOWDOWN_SUPERSCRIPT */
"LOWDOWN_FOOTNOTE", /* LOWDOWN_FOOTNOTE */
"LOWDOWN_MATH_BLOCK", /* LOWDOWN_MATH_BLOCK */
"LOWDOWN_RAW_HTML", /* LOWDOWN_RAW_HTML */
"LOWDOWN_ENTITY", /* LOWDOWN_ENTITY */
"LOWDOWN_NORMAL_TEXT", /* LOWDOWN_NORMAL_TEXT */
"LOWDOWN_DOC_HEADER", /* LOWDOWN_DOC_HEADER */
"LOWDOWN_META", /* LOWDOWN_META */
};
static int
rndr_indent(struct lowdown_buf *ob, size_t indent)
{
size_t i;
for (i = 0; i < indent; i++)
if (!HBUF_PUTSL(ob, " "))
return 0;
return 1;
}
static int
rndr_short(struct lowdown_buf *ob, const struct lowdown_buf *b)
{
size_t i;
for (i = 0; i < 20 && i < b->size; i++)
if (b->data[i] == '\n') {
if (!HBUF_PUTSL(ob, "\\n"))
return 0;
} else if (b->data[i] == '\t') {
if (!HBUF_PUTSL(ob, "\\t"))
return 0;
} else if (iscntrl((unsigned char)b->data[i])) {
if (!hbuf_putc(ob, '?'))
return 0;
} else {
if (!hbuf_putc(ob, b->data[i]))
return 0;
}
if (i < b->size && !HBUF_PUTSL(ob, "..."))
return 0;
return 1;
}
static int
rndr(struct lowdown_buf *ob,
const struct lowdown_node *root, size_t indent)
{
const struct lowdown_node *n;
struct lowdown_buf *tmp;
if (!rndr_indent(ob, indent))
return 0;
if (root->chng == LOWDOWN_CHNG_INSERT &&
!HBUF_PUTSL(ob, "INSERT: "))
return 0;
if (root->chng == LOWDOWN_CHNG_DELETE &&
!HBUF_PUTSL(ob, "DELETE: "))
return 0;
if (!hbuf_printf(ob, "%s (%zu)", names[root->type], root->id))
return 0;
if (!hbuf_putc(ob, '\n'))
return 0;
switch (root->type) {
case LOWDOWN_PARAGRAPH:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "lines: %zu, blank-after: %d\n",
root->rndr_paragraph.lines,
root->rndr_paragraph.beoln))
return 0;
break;
case LOWDOWN_IMAGE:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "source: "))
return 0;
if (!rndr_short(ob, &root->rndr_image.link))
return 0;
if (root->rndr_image.dims.size) {
if (!HBUF_PUTSL(ob, "("))
return 0;
if (!rndr_short(ob, &root->rndr_image.dims))
return 0;
if (!HBUF_PUTSL(ob, ")"))
return 0;
}
if (!HBUF_PUTSL(ob, "\n"))
return 0;
if (root->rndr_image.title.size) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "title: "))
return 0;
if (!rndr_short(ob, &root->rndr_image.title))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
if (root->rndr_image.alt.size) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "alt: "))
return 0;
if (!rndr_short(ob, &root->rndr_image.alt))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
if (root->rndr_image.dims.size) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "dims: "))
return 0;
if (!rndr_short(ob, &root->rndr_image.dims))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
if (root->rndr_image.attr_width.size) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "width (extended): "))
return 0;
if (!rndr_short(ob, &root->rndr_image.attr_width))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
if (root->rndr_image.attr_height.size) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "height (extended): "))
return 0;
if (!rndr_short(ob, &root->rndr_image.attr_height))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
if (root->rndr_image.attr_cls.size > 0) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!HBUF_PUTSL(ob, "class: "))
return 0;
if (!hbuf_putb(ob, &root->rndr_image.attr_cls))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
if (root->rndr_image.attr_id.size > 0) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!HBUF_PUTSL(ob, "id: "))
return 0;
if (!hbuf_putb(ob, &root->rndr_image.attr_id))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
break;
case LOWDOWN_HEADER:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "level: %zu\n",
root->rndr_header.level))
return 0;
if (root->rndr_header.attr_cls.size > 0) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!HBUF_PUTSL(ob, "class: "))
return 0;
if (!hbuf_putb(ob, &root->rndr_header.attr_cls))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
if (root->rndr_header.attr_id.size > 0) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!HBUF_PUTSL(ob, "id: "))
return 0;
if (!hbuf_putb(ob, &root->rndr_header.attr_id))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
break;
case LOWDOWN_RAW_HTML:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "data: %zu Bytes: ",
root->rndr_raw_html.text.size))
return 0;
if (!rndr_short(ob, &root->rndr_raw_html.text))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
break;
case LOWDOWN_BLOCKHTML:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "data: %zu Bytes: ",
root->rndr_blockhtml.text.size))
return 0;
if (!rndr_short(ob, &root->rndr_blockhtml.text))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
break;
case LOWDOWN_BLOCKCODE:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "data: %zu Bytes: ",
root->rndr_blockcode.text.size))
return 0;
if (!rndr_short(ob, &root->rndr_blockcode.text))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
break;
case LOWDOWN_DEFINITION:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "scope: %s\n",
HLIST_FL_BLOCK & root->rndr_definition.flags ?
"block" : "span"))
return 0;
break;
case LOWDOWN_TABLE_BLOCK:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "columns: %zu\n",
root->rndr_table.columns))
return 0;
break;
case LOWDOWN_TABLE_CELL:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "current: %zu\n",
root->rndr_table_cell.col))
return 0;
break;
case LOWDOWN_LISTITEM:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "scope: %s\n",
(root->rndr_listitem.flags & HLIST_FL_BLOCK) ?
"block" : "span"))
return 0;
if (!(root->rndr_listitem.flags &
(HLIST_FL_CHECKED | HLIST_FL_UNCHECKED)))
break;
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "check status: %s\n",
(root->rndr_listitem.flags & HLIST_FL_CHECKED) ?
"checked" : "unchecked"))
return 0;
break;
case LOWDOWN_LIST:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "list type: %s\n",
HLIST_FL_ORDERED & root->rndr_list.flags ?
"ordered" : "unordered"))
return 0;
break;
case LOWDOWN_META:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "key: "))
return 0;
if (!rndr_short(ob, &root->rndr_meta.key))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
break;
case LOWDOWN_MATH_BLOCK:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "blockmode: %s\n",
root->rndr_math.blockmode ?
"block" : "inline"))
return 0;
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "data: %zu Bytes: ",
root->rndr_math.text.size))
return 0;
if (!rndr_short(ob, &root->rndr_math.text))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
break;
case LOWDOWN_ENTITY:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "value: "))
return 0;
if (!rndr_short(ob, &root->rndr_entity.text))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
break;
case LOWDOWN_LINK_AUTO:
if (root->rndr_autolink.link.size) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!HBUF_PUTSL(ob, "link: "))
return 0;
if (!rndr_short(ob, &root->rndr_autolink.link))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
break;
case LOWDOWN_LINK:
if (root->rndr_link.title.size) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!HBUF_PUTSL(ob, "title: "))
return 0;
if (!rndr_short(ob, &root->rndr_link.title))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
if (root->rndr_link.link.size) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!HBUF_PUTSL(ob, "link: "))
return 0;
if (!rndr_short(ob, &root->rndr_link.link))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
if (root->rndr_link.attr_cls.size > 0) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!HBUF_PUTSL(ob, "class: "))
return 0;
if (!hbuf_putb(ob, &root->rndr_link.attr_cls))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
if (root->rndr_link.attr_id.size > 0) {
if (!rndr_indent(ob, indent + 1))
return 0;
if (!HBUF_PUTSL(ob, "id: "))
return 0;
if (!hbuf_putb(ob, &root->rndr_link.attr_id))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
}
break;
case LOWDOWN_NORMAL_TEXT:
if (!rndr_indent(ob, indent + 1))
return 0;
if (!hbuf_printf(ob, "data: %zu Bytes: ",
root->rndr_normal_text.text.size))
return 0;
if (!rndr_short(ob, &root->rndr_normal_text.text))
return 0;
if (!HBUF_PUTSL(ob, "\n"))
return 0;
break;
default:
break;
}
if ((tmp = hbuf_new(64)) == NULL)
return 0;
TAILQ_FOREACH(n, &root->children, entries)
if (!rndr(tmp, n, indent + 1)) {
hbuf_free(tmp);
return 0;
}
hbuf_putb(ob, tmp);
hbuf_free(tmp);
return 1;
}
int
lowdown_tree_rndr(struct lowdown_buf *ob,
const struct lowdown_node *root)
{
return rndr(ob, root, 0);
}