summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commonmark.c186
-rw-r--r--src/latex.c166
-rw-r--r--src/render.c29
-rw-r--r--src/render.h17
4 files changed, 198 insertions, 200 deletions
diff --git a/src/commonmark.c b/src/commonmark.c
index 5bbc8d4..274d4bc 100644
--- a/src/commonmark.c
+++ b/src/commonmark.c
@@ -12,6 +12,12 @@
#include "scanners.h"
#include "render.h"
+#define safe_strlen(s) cmark_strbuf_safe_strlen(s)
+#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
+#define LIT(s) renderer->out(renderer, s, false, LITERAL)
+#define CR() renderer->cr(renderer)
+#define BLANKLINE() renderer->blankline(renderer)
+
// Functions to convert cmark_nodes to commonmark strings.
static inline void outc(cmark_renderer *renderer,
@@ -58,13 +64,14 @@ static inline void outc(cmark_renderer *renderer,
}
static int
-longest_backtick_sequence(cmark_chunk *code)
+longest_backtick_sequence(const char *code)
{
int longest = 0;
int current = 0;
- int i = 0;
- while (i <= code->len) {
- if (code->data[i] == '`') {
+ size_t i = 0;
+ size_t code_len = safe_strlen(code);
+ while (i <= code_len) {
+ if (code[i] == '`') {
current++;
} else {
if (current > longest) {
@@ -78,13 +85,14 @@ longest_backtick_sequence(cmark_chunk *code)
}
static int
-shortest_unused_backtick_sequence(cmark_chunk *code)
+shortest_unused_backtick_sequence(const char *code)
{
int32_t used = 1;
int current = 0;
- int i = 0;
- while (i <= code->len) {
- if (code->data[i] == '`') {
+ size_t i = 0;
+ size_t code_len = safe_strlen(code);
+ while (i <= code_len) {
+ if (code[i] == '`') {
current++;
} else {
if (current) {
@@ -159,14 +167,13 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
cmark_renderer *renderer)
{
cmark_node *tmp;
- cmark_chunk *code;
int list_number;
cmark_delim_type list_delim;
int numticks;
int i;
bool entering = (ev_type == CMARK_EVENT_ENTER);
- cmark_chunk *info;
- cmark_chunk *title;
+ size_t info_len;
+ size_t code_len;
cmark_strbuf listmarker = GH_BUF_INIT;
char *emph_delim;
bufsize_t marker_width;
@@ -195,12 +202,12 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
case CMARK_NODE_BLOCK_QUOTE:
if (entering) {
- lit(renderer, "> ", false);
+ LIT("> ");
cmark_strbuf_puts(renderer->prefix, "> ");
} else {
cmark_strbuf_truncate(renderer->prefix,
renderer->prefix->size - 2);
- blankline(renderer);
+ BLANKLINE();
}
break;
@@ -210,7 +217,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
node->next->type == CMARK_NODE_LIST)) {
// this ensures 2 blank lines after list,
// if before code block or list:
- lit(renderer, "\n", false);
+ LIT("\n");
renderer->need_cr = 0;
}
break;
@@ -240,10 +247,10 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
if (entering) {
if (cmark_node_get_list_type(node->parent) ==
CMARK_BULLET_LIST) {
- lit(renderer, "* ", false);
+ LIT("* ");
cmark_strbuf_puts(renderer->prefix, " ");
} else {
- lit(renderer, (char *)listmarker.ptr, false);
+ LIT((char *)listmarker.ptr);
for (i = marker_width; i--;) {
cmark_strbuf_putc(renderer->prefix, ' ');
}
@@ -252,7 +259,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
cmark_strbuf_truncate(renderer->prefix,
renderer->prefix->size -
marker_width);
- cr(renderer);
+ CR();
}
cmark_strbuf_free(&listmarker);
break;
@@ -260,33 +267,35 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
case CMARK_NODE_HEADER:
if (entering) {
for (int i = cmark_node_get_header_level(node); i > 0; i--) {
- lit(renderer, "#", false);
+ LIT("#");
}
- lit(renderer, " ", false);
+ LIT(" ");
renderer->no_wrap = true;
} else {
renderer->no_wrap = false;
- blankline(renderer);
+ BLANKLINE();
}
break;
case CMARK_NODE_CODE_BLOCK:
- blankline(renderer);
- info = &node->as.code.info;
- code = &node->as.code.literal;
+ BLANKLINE();
+ const char* info = cmark_node_get_fence_info(node);
+ info_len = safe_strlen(info);
+ const char* code = cmark_node_get_literal(node);
+ code_len = safe_strlen(code);
// use indented form if no info, and code doesn't
// begin or end with a blank line, and code isn't
// first thing in a list item
- if (info->len == 0 &&
- (code->len > 2 &&
- !isspace(code->data[0]) &&
- !(isspace(code->data[code->len - 1]) &&
- isspace(code->data[code->len - 2]))) &&
+ if (info_len == 0 &&
+ (code_len > 2 &&
+ !isspace(code[0]) &&
+ !(isspace(code[code_len - 1]) &&
+ isspace(code[code_len - 2]))) &&
!(node->prev == NULL && node->parent &&
node->parent->type == CMARK_NODE_ITEM)) {
- lit(renderer, " ", false);
+ LIT(" ");
cmark_strbuf_puts(renderer->prefix, " ");
- out(renderer, node->as.code.literal, false, LITERAL);
+ OUT(cmark_node_get_literal(node), false, LITERAL);
cmark_strbuf_truncate(renderer->prefix,
renderer->prefix->size - 4);
} else {
@@ -295,84 +304,85 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
numticks = 3;
}
for (i = 0; i < numticks; i++) {
- lit(renderer, "`", false);
+ LIT("`");
}
- lit(renderer, " ", false);
- out(renderer, *info, false, LITERAL);
- cr(renderer);
- out(renderer, node->as.code.literal, false, LITERAL);
- cr(renderer);
+ LIT(" ");
+ OUT(info, false, LITERAL);
+ CR();
+ OUT(cmark_node_get_literal(node), false, LITERAL);
+ CR();
for (i = 0; i < numticks; i++) {
- lit(renderer, "`", false);
+ LIT("`");
}
}
- blankline(renderer);
+ BLANKLINE();
break;
case CMARK_NODE_HTML:
- blankline(renderer);
- out(renderer, node->as.literal, false, LITERAL);
- blankline(renderer);
+ BLANKLINE();
+ OUT(cmark_node_get_literal(node), false, LITERAL);
+ BLANKLINE();
break;
case CMARK_NODE_HRULE:
- blankline(renderer);
- lit(renderer, "-----", false);
- blankline(renderer);
+ BLANKLINE();
+ LIT("-----");
+ BLANKLINE();
break;
case CMARK_NODE_PARAGRAPH:
if (!entering) {
- blankline(renderer);
+ BLANKLINE();
}
break;
case CMARK_NODE_TEXT:
- out(renderer, node->as.literal, true, NORMAL);
+ OUT(cmark_node_get_literal(node), true, NORMAL);
break;
case CMARK_NODE_LINEBREAK:
if (!(CMARK_OPT_HARDBREAKS & renderer->options)) {
- lit(renderer, "\\", false);
+ LIT("\\");
}
- cr(renderer);
+ CR();
break;
case CMARK_NODE_SOFTBREAK:
if (renderer->width == 0) {
- cr(renderer);
+ CR();
} else {
- lit(renderer, " ", true);
+ OUT(" ", true, LITERAL);
}
break;
case CMARK_NODE_CODE:
- code = &node->as.literal;
+ code = cmark_node_get_literal(node);
+ code_len = safe_strlen(code);
numticks = shortest_unused_backtick_sequence(code);
for (i = 0; i < numticks; i++) {
- lit(renderer, "`", false);
+ LIT("`");
}
- if (code->len == 0 || code->data[0] == '`') {
- lit(renderer, " ", false);
+ if (code_len == 0 || code[0] == '`') {
+ LIT(" ");
}
- out(renderer, node->as.literal, true, LITERAL);
- if (code->len == 0 || code->data[code->len - 1] == '`') {
- lit(renderer, " ", false);
+ OUT(cmark_node_get_literal(node), true, LITERAL);
+ if (code_len == 0 || code[code_len - 1] == '`') {
+ LIT(" ");
}
for (i = 0; i < numticks; i++) {
- lit(renderer, "`", false);
+ LIT("`");
}
break;
case CMARK_NODE_INLINE_HTML:
- out(renderer, node->as.literal, false, LITERAL);
+ OUT(cmark_node_get_literal(node), false, LITERAL);
break;
case CMARK_NODE_STRONG:
if (entering) {
- lit(renderer, "**", false);
+ LIT("**");
} else {
- lit(renderer, "**", false);
+ LIT("**");
}
break;
@@ -386,62 +396,56 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
emph_delim = "*";
}
if (entering) {
- lit(renderer, emph_delim, false);
+ LIT(emph_delim);
} else {
- lit(renderer, emph_delim, false);
+ LIT(emph_delim);
}
break;
case CMARK_NODE_LINK:
if (is_autolink(node)) {
if (entering) {
- lit(renderer, "<", false);
+ LIT("<");
if (strncmp(cmark_node_get_url(node),
"mailto:", 7) == 0) {
- lit(renderer,
- (char *)cmark_node_get_url(node) + 7,
- false);
+ LIT((char *)cmark_node_get_url(node) + 7);
} else {
- lit(renderer,
- (char *)cmark_node_get_url(node),
- false);
+ LIT((char *)cmark_node_get_url(node));
}
- lit(renderer, ">", false);
+ LIT(">");
// return signal to skip contents of node...
return 0;
}
} else {
if (entering) {
- lit(renderer, "[", false);
+ LIT("[");
} else {
- lit(renderer, "](", false);
- out(renderer,
- cmark_chunk_literal(cmark_node_get_url(node)),
- false, URL);
- title = &node->as.link.title;
- if (title->len > 0) {
- lit(renderer, " \"", true);
- out(renderer, *title, false, TITLE);
- lit(renderer, "\"", false);
+ LIT("](");
+ OUT(cmark_node_get_url(node), false, URL);
+ const char* title = cmark_node_get_title(node);
+ if (safe_strlen(title) > 0) {
+ LIT(" \"");
+ OUT(title, false, TITLE);
+ LIT("\"");
}
- lit(renderer, ")", false);
+ LIT(")");
}
}
break;
case CMARK_NODE_IMAGE:
if (entering) {
- lit(renderer, "![", false);
+ LIT("![");
} else {
- lit(renderer, "](", false);
- out(renderer, cmark_chunk_literal(cmark_node_get_url(node)), false, URL);
- title = &node->as.link.title;
- if (title->len > 0) {
- lit(renderer, " \"", true);
- out(renderer, *title, false, TITLE);
- lit(renderer, "\"", false);
+ LIT("](");
+ OUT(cmark_node_get_url(node), false, URL);
+ const char* title = cmark_node_get_title(node);
+ if (safe_strlen(title) > 0) {
+ OUT(" \"", true, LITERAL);
+ OUT(title, false, TITLE);
+ LIT("\"");
}
- lit(renderer, ")", false);
+ LIT(")");
}
break;
diff --git a/src/latex.c b/src/latex.c
index 6cca96e..058f212 100644
--- a/src/latex.c
+++ b/src/latex.c
@@ -12,6 +12,12 @@
#include "scanners.h"
#include "render.h"
+#define safe_strlen(s) cmark_strbuf_safe_strlen(s)
+#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
+#define LIT(s) renderer->out(renderer, s, false, LITERAL)
+#define CR() renderer->cr(renderer)
+#define BLANKLINE() renderer->blankline(renderer)
+
static inline void outc(cmark_renderer *renderer,
cmark_escaping escape,
int32_t c,
@@ -188,8 +194,7 @@ typedef enum {
static link_type
get_link_type(cmark_node *node)
{
- cmark_chunk *title;
- cmark_chunk *url;
+ size_t title_len, url_len;
cmark_node *link_text;
char *realurl;
int realurllen;
@@ -199,21 +204,25 @@ get_link_type(cmark_node *node)
return NO_LINK;
}
- url = &node->as.link.url;
- if (url->len == 0 || scan_scheme(url, 0) == 0) {
+ const char* url = cmark_node_get_url(node);
+ cmark_chunk url_chunk = cmark_chunk_literal(url);
+
+ url_len = safe_strlen(url);
+ if (url_len == 0 || scan_scheme(&url_chunk, 0) == 0) {
return NO_LINK;
}
- title = &node->as.link.title;
+ const char* title = cmark_node_get_title(node);
+ title_len = safe_strlen(title);
// if it has a title, we can't treat it as an autolink:
- if (title->len > 0) {
+ if (title_len > 0) {
return NORMAL_LINK;
}
link_text = node->first_child;
cmark_consolidate_text_nodes(link_text);
- realurl = (char*)url->data;
- realurllen = url->len;
+ realurl = (char*)url;
+ realurllen = url_len;
if (strncmp(realurl, "mailto:", 7) == 0) {
realurl += 7;
realurllen -= 7;
@@ -255,7 +264,6 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
char list_number_string[20];
bool entering = (ev_type == CMARK_EVENT_ENTER);
cmark_list_type list_type;
- cmark_chunk url;
const char* roman_numerals[] = { "", "i", "ii", "iii", "iv", "v",
"vi", "vii", "viii", "ix", "x"
};
@@ -284,11 +292,11 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
case CMARK_NODE_BLOCK_QUOTE:
if (entering) {
- lit(renderer, "\\begin{quote}", false);
- cr(renderer);
+ LIT("\\begin{quote}");
+ CR();
} else {
- lit(renderer, "\\end{quote}", false);
- blankline(renderer);
+ LIT("\\end{quote}");
+ BLANKLINE();
}
break;
@@ -298,44 +306,39 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
if (list_type == CMARK_ORDERED_LIST) {
renderer->enumlevel++;
}
- lit(renderer, "\\begin{", false);
- lit(renderer,
- list_type == CMARK_ORDERED_LIST ?
- "enumerate" : "itemize", false);
- lit(renderer, "}", false);
- cr(renderer);
+ LIT("\\begin{");
+ LIT(list_type == CMARK_ORDERED_LIST ?
+ "enumerate" : "itemize");
+ LIT("}");
+ CR();
list_number = cmark_node_get_list_start(node);
if (list_number > 1) {
sprintf(list_number_string,
"%d", list_number);
- lit(renderer, "\\setcounter{enum", false);
- lit(renderer, (char *)roman_numerals[renderer->enumlevel],
- false);
- lit(renderer, "}{", false);
- out(renderer,
- cmark_chunk_literal(list_number_string),
- false, NORMAL);
- lit(renderer, "}", false);
- cr(renderer);
+ LIT("\\setcounter{enum");
+ LIT((char *)roman_numerals[renderer->enumlevel]);
+ LIT("}{");
+ OUT(list_number_string, false, NORMAL);
+ LIT("}");
+ CR();
}
} else {
if (list_type == CMARK_ORDERED_LIST) {
renderer->enumlevel--;
}
- lit(renderer, "\\end{", false);
- lit(renderer,
- list_type == CMARK_ORDERED_LIST ?
- "enumerate" : "itemize", false);
- lit(renderer, "}", false);
- blankline(renderer);
+ LIT("\\end{");
+ LIT(list_type == CMARK_ORDERED_LIST ?
+ "enumerate" : "itemize");
+ LIT("}");
+ BLANKLINE();
}
break;
case CMARK_NODE_ITEM:
if (entering) {
- lit(renderer, "\\item ", false);
+ LIT("\\item ");
} else {
- cr(renderer);
+ CR();
}
break;
@@ -343,74 +346,74 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
if (entering) {
switch (cmark_node_get_header_level(node)) {
case 1:
- lit(renderer, "\\section", false);
+ LIT("\\section");
break;
case 2:
- lit(renderer, "\\subsection", false);
+ LIT("\\subsection");
break;
case 3:
- lit(renderer, "\\subsubsection", false);
+ LIT("\\subsubsection");
break;
case 4:
- lit(renderer, "\\paragraph", false);
+ LIT("\\paragraph");
break;
case 5:
- lit(renderer, "\\subparagraph", false);
+ LIT("\\subparagraph");
break;
}
- lit(renderer, "{", false);
+ LIT("{");
} else {
- lit(renderer, "}", false);
- blankline(renderer);
+ LIT("}");
+ BLANKLINE();
}
break;
case CMARK_NODE_CODE_BLOCK:
- cr(renderer);
- lit(renderer, "\\begin{verbatim}", false);
- cr(renderer);
- out(renderer, node->as.code.literal, false, LITERAL);
- cr(renderer);
- lit(renderer, "\\end{verbatim}", false);
- blankline(renderer);
+ CR();
+ LIT("\\begin{verbatim}");
+ CR();
+ OUT(cmark_node_get_literal(node), false, LITERAL);
+ CR();
+ LIT("\\end{verbatim}");
+ BLANKLINE();
break;
case CMARK_NODE_HTML:
break;
case CMARK_NODE_HRULE:
- blankline(renderer);
- lit(renderer, "\\begin{center}\\rule{0.5\\linewidth}{\\linethickness}\\end{center}", false);
- blankline(renderer);
+ BLANKLINE();
+ LIT("\\begin{center}\\rule{0.5\\linewidth}{\\linethickness}\\end{center}");
+ BLANKLINE();
break;
case CMARK_NODE_PARAGRAPH:
if (!entering) {
- blankline(renderer);
+ BLANKLINE();
}
break;
case CMARK_NODE_TEXT:
- out(renderer, node->as.literal, true, NORMAL);
+ OUT(cmark_node_get_literal(node), true, NORMAL);
break;
case CMARK_NODE_LINEBREAK:
- lit(renderer, "\\\\", false);
- cr(renderer);
+ LIT("\\\\");
+ CR();
break;
case CMARK_NODE_SOFTBREAK:
if (renderer->width == 0) {
- cr(renderer);
+ CR();
} else {
- lit(renderer, " ", true);
+ OUT(" ", true, NORMAL);
}
break;
case CMARK_NODE_CODE:
- lit(renderer, "\\texttt{", false);
- out(renderer, node->as.literal, false, NORMAL);
- lit(renderer, "}", false);
+ LIT("\\texttt{");
+ OUT(cmark_node_get_literal(node), false, NORMAL);
+ LIT("}");
break;
case CMARK_NODE_INLINE_HTML:
@@ -418,55 +421,54 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
case CMARK_NODE_STRONG:
if (entering) {
- lit(renderer, "\\textbf{", false);
+ LIT("\\textbf{");
} else {
- lit(renderer, "}", false);
+ LIT("}");
}
break;
case CMARK_NODE_EMPH:
if (entering) {
- lit(renderer, "\\emph{", false);
+ LIT("\\emph{");
} else {
- lit(renderer, "}", false);
+ LIT("}");
}
break;
case CMARK_NODE_LINK:
if (entering) {
- url = cmark_chunk_literal(cmark_node_get_url(node));
+ const char* url = cmark_node_get_url(node);
// requires \usepackage{hyperref}
switch(get_link_type(node)) {
case URL_AUTOLINK:
- lit(renderer, "\\url{", false);
- out(renderer, url, false, URL);
+ LIT("\\url{");
+ OUT(url, false, URL);
break;
case EMAIL_AUTOLINK:
- lit(renderer, "\\href{", false);
- out(renderer, url, false, URL);
- lit(renderer, "}\\nolinkurl{", false);
+ LIT("\\href{");
+ OUT(url, false, URL);
+ LIT("}\\nolinkurl{");
break;
case NORMAL_LINK:
- lit(renderer, "\\href{", false);
- out(renderer, url, false, URL);
- lit(renderer, "}{", false);
+ LIT("\\href{");
+ OUT(url, false, URL);
+ LIT("}{");
break;
case NO_LINK:
- lit(renderer, "{", false); // error?
+ LIT("{"); // error?
}
} else {
- lit(renderer, "}", false);
+ LIT("}");
}
break;
case CMARK_NODE_IMAGE:
if (entering) {
- url = cmark_chunk_literal(cmark_node_get_url(node));
- lit(renderer, "\\protect\\includegraphics{", false);
+ LIT("\\protect\\includegraphics{");
// requires \include{graphicx}
- out(renderer, url, false, URL);
- lit(renderer, "}", false);
+ OUT(cmark_node_get_url(node), false, URL);
+ LIT("}");
return 0;
}
break;
diff --git a/src/render.c b/src/render.c
index 442a7fc..16caadc 100644
--- a/src/render.c
+++ b/src/render.c
@@ -5,27 +5,29 @@
#include "utf8.h"
#include "render.h"
-void cr(cmark_renderer *renderer)
+static inline
+void S_cr(cmark_renderer *renderer)
{
if (renderer->need_cr < 1) {
renderer->need_cr = 1;
}
}
-void blankline(cmark_renderer *renderer)
+static inline
+void S_blankline(cmark_renderer *renderer)
{
if (renderer->need_cr < 2) {
renderer->need_cr = 2;
}
}
-void out(cmark_renderer *renderer,
- cmark_chunk str,
- bool wrap,
- cmark_escaping escape)
+static
+void S_out(cmark_renderer *renderer,
+ const char *source,
+ bool wrap,
+ cmark_escaping escape)
{
- unsigned char* source = str.data;
- int length = str.len;
+ int length = cmark_strbuf_safe_strlen(source);
unsigned char nextc;
int32_t c;
int i = 0;
@@ -61,7 +63,7 @@ void out(cmark_renderer *renderer,
renderer->column = renderer->prefix->size;
}
- len = utf8proc_iterate(source + i, length - i, &c);
+ len = utf8proc_iterate((const uint8_t *)source + i, length - i, &c);
if (len == -1) { // error condition
return; // return without rendering rest of string
}
@@ -114,12 +116,6 @@ void out(cmark_renderer *renderer,
}
}
-void lit(cmark_renderer *renderer, char *s, bool wrap)
-{
- cmark_chunk str = cmark_chunk_literal(s);
- out(renderer, str, wrap, LITERAL);
-}
-
char*
cmark_render(cmark_node *root,
int options,
@@ -145,7 +141,8 @@ cmark_render(cmark_node *root,
}
cmark_renderer renderer = { options, &buf, &pref, 0, width,
- 0, 0, 0, true, false, false, outc };
+ 0, 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);
diff --git a/src/render.h b/src/render.h
index 718050e..cf5b078 100644
--- a/src/render.h
+++ b/src/render.h
@@ -32,21 +32,16 @@ struct cmark_renderer {
cmark_escaping,
int32_t,
unsigned char);
+ void (*cr)(struct cmark_renderer*);
+ void (*blankline)(struct cmark_renderer*);
+ void (*out)(struct cmark_renderer*,
+ const char *,
+ bool,
+ cmark_escaping);
};
typedef struct cmark_renderer cmark_renderer;
-void cr(cmark_renderer *renderer);
-
-void blankline(cmark_renderer *renderer);
-
-void out(cmark_renderer *renderer,
- cmark_chunk str,
- bool wrap,
- cmark_escaping escape);
-
-void lit(cmark_renderer *renderer, char *s, bool wrap);
-
char*
cmark_render(cmark_node *root,
int options,