Strip extensions API down and separate from core
This commit is contained in:
Родитель
c8960d74de
Коммит
3e3761a26e
17
Makefile
17
Makefile
|
@ -1,5 +1,4 @@
|
||||||
SRCDIR=src
|
SRCDIR=src
|
||||||
EXTDIR=extensions
|
|
||||||
DATADIR=data
|
DATADIR=data
|
||||||
BUILDDIR?=build
|
BUILDDIR?=build
|
||||||
GENERATOR?=Unix Makefiles
|
GENERATOR?=Unix Makefiles
|
||||||
|
@ -127,19 +126,6 @@ $(SRCDIR)/scanners.c: $(SRCDIR)/scanners.re
|
||||||
--encoding-policy substitute -o $@ $<
|
--encoding-policy substitute -o $@ $<
|
||||||
$(CLANG_FORMAT) $@
|
$(CLANG_FORMAT) $@
|
||||||
|
|
||||||
# We include scanners.c in the repository, so this shouldn't
|
|
||||||
# normally need to be generated.
|
|
||||||
$(EXTDIR)/ext_scanners.c: $(EXTDIR)/ext_scanners.re
|
|
||||||
@case "$$(re2c -v)" in \
|
|
||||||
*\ 0.13.*|*\ 0.14|*\ 0.14.1) \
|
|
||||||
echo "re2c >= 0.14.2 is required"; \
|
|
||||||
false; \
|
|
||||||
;; \
|
|
||||||
esac
|
|
||||||
re2c --case-insensitive -b -i --no-generation-date -8 \
|
|
||||||
--encoding-policy substitute -o $@ $<
|
|
||||||
clang-format -style llvm -i $@
|
|
||||||
|
|
||||||
# We include entities.inc in the repository, so normally this
|
# We include entities.inc in the repository, so normally this
|
||||||
# doesn't need to be regenerated:
|
# doesn't need to be regenerated:
|
||||||
$(SRCDIR)/entities.inc: tools/make_entities_inc.py
|
$(SRCDIR)/entities.inc: tools/make_entities_inc.py
|
||||||
|
@ -203,6 +189,9 @@ newbench:
|
||||||
format:
|
format:
|
||||||
$(CLANG_FORMAT) src/*.c src/*.h api_test/*.c api_test/*.h
|
$(CLANG_FORMAT) src/*.c src/*.h api_test/*.c api_test/*.h
|
||||||
|
|
||||||
|
format-extensions:
|
||||||
|
clang-format -style llvm -i extensions/*.c extensions/*.h
|
||||||
|
|
||||||
operf: $(CMARK)
|
operf: $(CMARK)
|
||||||
operf $< < $(BENCHFILE) > /dev/null
|
operf $< < $(BENCHFILE) > /dev/null
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ static void test_md_to_html(test_batch_runner *runner, const char *markdown,
|
||||||
const char *expected_html, const char *msg);
|
const char *expected_html, const char *msg);
|
||||||
|
|
||||||
static void test_content(test_batch_runner *runner, cmark_node_type type,
|
static void test_content(test_batch_runner *runner, cmark_node_type type,
|
||||||
int allowed_content);
|
unsigned int *allowed_content);
|
||||||
|
|
||||||
static void test_char(test_batch_runner *runner, int valid, const char *utf8,
|
static void test_char(test_batch_runner *runner, int valid, const char *utf8,
|
||||||
const char *msg);
|
const char *msg);
|
||||||
|
@ -177,7 +177,7 @@ static void accessors(test_batch_runner *runner) {
|
||||||
OK(runner, cmark_node_set_literal(string, literal + sizeof("prefix")),
|
OK(runner, cmark_node_set_literal(string, literal + sizeof("prefix")),
|
||||||
"set_literal suffix");
|
"set_literal suffix");
|
||||||
|
|
||||||
char *rendered_html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
|
char *rendered_html = cmark_render_html(doc, CMARK_OPT_DEFAULT, NULL);
|
||||||
static const char expected_html[] =
|
static const char expected_html[] =
|
||||||
"<h3>Header</h3>\n"
|
"<h3>Header</h3>\n"
|
||||||
"<ol start=\"3\">\n"
|
"<ol start=\"3\">\n"
|
||||||
|
@ -299,7 +299,7 @@ static void iterator_delete(test_batch_runner *runner) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
|
char *html = cmark_render_html(doc, CMARK_OPT_DEFAULT, NULL);
|
||||||
static const char expected[] = "<p>a c</p>\n"
|
static const char expected[] = "<p>a c</p>\n"
|
||||||
"<p>a c</p>\n";
|
"<p>a c</p>\n";
|
||||||
STR_EQ(runner, html, expected, "iterate and delete nodes");
|
STR_EQ(runner, html, expected, "iterate and delete nodes");
|
||||||
|
@ -339,7 +339,7 @@ static void create_tree(test_batch_runner *runner) {
|
||||||
OK(runner, cmark_node_append_child(emph, str2), "append3");
|
OK(runner, cmark_node_append_child(emph, str2), "append3");
|
||||||
INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append3 consistent");
|
INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append3 consistent");
|
||||||
|
|
||||||
html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
|
html = cmark_render_html(doc, CMARK_OPT_DEFAULT, NULL);
|
||||||
STR_EQ(runner, html, "<p>Hello, <em>world</em>!</p>\n", "render_html");
|
STR_EQ(runner, html, "<p>Hello, <em>world</em>!</p>\n", "render_html");
|
||||||
free(html);
|
free(html);
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ static void create_tree(test_batch_runner *runner) {
|
||||||
|
|
||||||
cmark_node_unlink(emph);
|
cmark_node_unlink(emph);
|
||||||
|
|
||||||
html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
|
html = cmark_render_html(doc, CMARK_OPT_DEFAULT, NULL);
|
||||||
STR_EQ(runner, html, "<p>brzz!</p>\n", "render_html after shuffling");
|
STR_EQ(runner, html, "<p>brzz!</p>\n", "render_html after shuffling");
|
||||||
free(html);
|
free(html);
|
||||||
|
|
||||||
|
@ -407,7 +407,7 @@ static void custom_nodes(test_batch_runner *runner) {
|
||||||
STR_EQ(runner, cmark_node_get_on_exit(cb), "", "get_on_exit (empty)");
|
STR_EQ(runner, cmark_node_get_on_exit(cb), "", "get_on_exit (empty)");
|
||||||
cmark_node_append_child(doc, cb);
|
cmark_node_append_child(doc, cb);
|
||||||
|
|
||||||
html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
|
html = cmark_render_html(doc, CMARK_OPT_DEFAULT, NULL);
|
||||||
STR_EQ(runner, html, "<p><ON ENTER|Hello|ON EXIT></p>\n<on enter|\n",
|
STR_EQ(runner, html, "<p><ON ENTER|Hello|ON EXIT></p>\n<on enter|\n",
|
||||||
"render_html");
|
"render_html");
|
||||||
free(html);
|
free(html);
|
||||||
|
@ -434,22 +434,18 @@ void hierarchy(test_batch_runner *runner) {
|
||||||
|
|
||||||
cmark_node_free(bquote1);
|
cmark_node_free(bquote1);
|
||||||
|
|
||||||
int max_node_type = CMARK_NODE_LAST_BLOCK > CMARK_NODE_LAST_INLINE
|
unsigned int list_item_flag[] = {CMARK_NODE_ITEM, 0};
|
||||||
? CMARK_NODE_LAST_BLOCK
|
unsigned int top_level_blocks[] = {
|
||||||
: CMARK_NODE_LAST_INLINE;
|
CMARK_NODE_BLOCK_QUOTE, CMARK_NODE_LIST,
|
||||||
OK(runner, max_node_type < 32, "all node types < 32");
|
CMARK_NODE_CODE_BLOCK, CMARK_NODE_HTML_BLOCK,
|
||||||
|
CMARK_NODE_PARAGRAPH, CMARK_NODE_HEADING,
|
||||||
int list_item_flag = 1 << CMARK_NODE_ITEM;
|
CMARK_NODE_THEMATIC_BREAK, 0};
|
||||||
int top_level_blocks =
|
unsigned int all_inlines[] = {
|
||||||
(1 << CMARK_NODE_BLOCK_QUOTE) | (1 << CMARK_NODE_LIST) |
|
CMARK_NODE_TEXT, CMARK_NODE_SOFTBREAK,
|
||||||
(1 << CMARK_NODE_CODE_BLOCK) | (1 << CMARK_NODE_HTML_BLOCK) |
|
CMARK_NODE_LINEBREAK, CMARK_NODE_CODE,
|
||||||
(1 << CMARK_NODE_PARAGRAPH) | (1 << CMARK_NODE_HEADING) |
|
CMARK_NODE_HTML_INLINE, CMARK_NODE_EMPH,
|
||||||
(1 << CMARK_NODE_THEMATIC_BREAK);
|
CMARK_NODE_STRONG, CMARK_NODE_LINK,
|
||||||
int all_inlines = (1 << CMARK_NODE_TEXT) | (1 << CMARK_NODE_SOFTBREAK) |
|
CMARK_NODE_IMAGE, 0};
|
||||||
(1 << CMARK_NODE_LINEBREAK) | (1 << CMARK_NODE_CODE) |
|
|
||||||
(1 << CMARK_NODE_HTML_INLINE) | (1 << CMARK_NODE_EMPH) |
|
|
||||||
(1 << CMARK_NODE_STRONG) | (1 << CMARK_NODE_LINK) |
|
|
||||||
(1 << CMARK_NODE_IMAGE);
|
|
||||||
|
|
||||||
test_content(runner, CMARK_NODE_DOCUMENT, top_level_blocks);
|
test_content(runner, CMARK_NODE_DOCUMENT, top_level_blocks);
|
||||||
test_content(runner, CMARK_NODE_BLOCK_QUOTE, top_level_blocks);
|
test_content(runner, CMARK_NODE_BLOCK_QUOTE, top_level_blocks);
|
||||||
|
@ -472,7 +468,7 @@ void hierarchy(test_batch_runner *runner) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_content(test_batch_runner *runner, cmark_node_type type,
|
static void test_content(test_batch_runner *runner, cmark_node_type type,
|
||||||
int allowed_content) {
|
unsigned int *allowed_content) {
|
||||||
cmark_node *node = cmark_node_new(type);
|
cmark_node *node = cmark_node_new(type);
|
||||||
|
|
||||||
for (int i = 0; i < num_node_types; ++i) {
|
for (int i = 0; i < num_node_types; ++i) {
|
||||||
|
@ -480,7 +476,10 @@ static void test_content(test_batch_runner *runner, cmark_node_type type,
|
||||||
cmark_node *child = cmark_node_new(child_type);
|
cmark_node *child = cmark_node_new(child_type);
|
||||||
|
|
||||||
int got = cmark_node_append_child(node, child);
|
int got = cmark_node_append_child(node, child);
|
||||||
int expected = (allowed_content >> child_type) & 1;
|
int expected = 0;
|
||||||
|
if (allowed_content)
|
||||||
|
for (unsigned int *p = allowed_content; *p; ++p)
|
||||||
|
expected |= *p == child_type;
|
||||||
|
|
||||||
INT_EQ(runner, got, expected, "add %d as child of %d", child_type, type);
|
INT_EQ(runner, got, expected, "add %d as child of %d", child_type, type);
|
||||||
|
|
||||||
|
@ -505,17 +504,17 @@ static void render_html(test_batch_runner *runner) {
|
||||||
cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
|
cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
|
||||||
|
|
||||||
cmark_node *paragraph = cmark_node_first_child(doc);
|
cmark_node *paragraph = cmark_node_first_child(doc);
|
||||||
html = cmark_render_html(paragraph, CMARK_OPT_DEFAULT);
|
html = cmark_render_html(paragraph, CMARK_OPT_DEFAULT, NULL);
|
||||||
STR_EQ(runner, html, "<p>foo <em>bar</em></p>\n", "render single paragraph");
|
STR_EQ(runner, html, "<p>foo <em>bar</em></p>\n", "render single paragraph");
|
||||||
free(html);
|
free(html);
|
||||||
|
|
||||||
cmark_node *string = cmark_node_first_child(paragraph);
|
cmark_node *string = cmark_node_first_child(paragraph);
|
||||||
html = cmark_render_html(string, CMARK_OPT_DEFAULT);
|
html = cmark_render_html(string, CMARK_OPT_DEFAULT, NULL);
|
||||||
STR_EQ(runner, html, "foo ", "render single inline");
|
STR_EQ(runner, html, "foo ", "render single inline");
|
||||||
free(html);
|
free(html);
|
||||||
|
|
||||||
cmark_node *emph = cmark_node_next(string);
|
cmark_node *emph = cmark_node_next(string);
|
||||||
html = cmark_render_html(emph, CMARK_OPT_DEFAULT);
|
html = cmark_render_html(emph, CMARK_OPT_DEFAULT, NULL);
|
||||||
STR_EQ(runner, html, "<em>bar</em>", "render inline with children");
|
STR_EQ(runner, html, "<em>bar</em>", "render inline with children");
|
||||||
free(html);
|
free(html);
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
set(LIBRARY "cmarkextensions")
|
set(STATICLIBRARY "libcmarkextensions_static")
|
||||||
set(LIBRARY_SOURCES
|
set(LIBRARY_SOURCES
|
||||||
${PROJECT_SOURCE_DIR}/src/buffer.c
|
|
||||||
${PROJECT_SOURCE_DIR}/src/cmark_ctype.c
|
|
||||||
core-extensions.c
|
core-extensions.c
|
||||||
ext_scanners.c
|
|
||||||
ext_scanners.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
|
@ -27,6 +23,54 @@ include_directories(. ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE} -pg")
|
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE} -pg")
|
||||||
set(CMAKE_LINKER_PROFILE "${CMAKE_LINKER_FLAGS_RELEASE} -pg")
|
set(CMAKE_LINKER_PROFILE "${CMAKE_LINKER_FLAGS_RELEASE} -pg")
|
||||||
|
|
||||||
add_library(${LIBRARY} SHARED ${LIBRARY_SOURCES})
|
add_library(${STATICLIBRARY} STATIC ${LIBRARY_SOURCES})
|
||||||
|
|
||||||
target_link_libraries(cmarkextensions libcmark)
|
set_target_properties(${STATICLIBRARY} PROPERTIES
|
||||||
|
COMPILE_FLAGS -DCMARK_STATIC_DEFINE
|
||||||
|
POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
set_target_properties(${STATICLIBRARY} PROPERTIES
|
||||||
|
OUTPUT_NAME "cmarkextensions_static"
|
||||||
|
VERSION ${PROJECT_VERSION})
|
||||||
|
else()
|
||||||
|
set_target_properties(${STATICLIBRARY} PROPERTIES
|
||||||
|
OUTPUT_NAME "cmarkextensions"
|
||||||
|
VERSION ${PROJECT_VERSION})
|
||||||
|
endif(MSVC)
|
||||||
|
|
||||||
|
# Feature tests
|
||||||
|
include(CheckIncludeFile)
|
||||||
|
include(CheckCSourceCompiles)
|
||||||
|
include(CheckCSourceRuns)
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H)
|
||||||
|
CHECK_C_SOURCE_COMPILES(
|
||||||
|
"int main() { __builtin_expect(0,0); return 0; }"
|
||||||
|
HAVE___BUILTIN_EXPECT)
|
||||||
|
CHECK_C_SOURCE_COMPILES("
|
||||||
|
int f(void) __attribute__ (());
|
||||||
|
int main() { return 0; }
|
||||||
|
" HAVE___ATTRIBUTE__)
|
||||||
|
|
||||||
|
# Always compile with warnings
|
||||||
|
if(MSVC)
|
||||||
|
# Force to always compile with W4
|
||||||
|
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||||
|
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||||
|
else()
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
|
||||||
|
endif()
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4706 /D_CRT_SECURE_NO_WARNINGS")
|
||||||
|
elseif(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -std=c99 -pedantic")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Compile as C++ under MSVC older than 12.0
|
||||||
|
if(MSVC AND MSVC_VERSION LESS 1800)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /TP")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_BUILD_TYPE STREQUAL "Ubsan")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined")
|
||||||
|
endif()
|
||||||
|
|
|
@ -1,325 +1,3 @@
|
||||||
#include <stdio.h>
|
#include "core-extensions.h"
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <cmark.h>
|
int core_extensions_registration(cmark_plugin *plugin) { return 1; }
|
||||||
#include <cmark_extension_api.h>
|
|
||||||
|
|
||||||
#include "parser.h"
|
|
||||||
#include "buffer.h"
|
|
||||||
#include "ext_scanners.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int n_columns;
|
|
||||||
cmark_llist *cells;
|
|
||||||
} table_row;
|
|
||||||
|
|
||||||
static void free_table_cell(void *data) {
|
|
||||||
cmark_strbuf_free((cmark_strbuf *) data);
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_table_row(table_row *row) {
|
|
||||||
|
|
||||||
if (!row)
|
|
||||||
return;
|
|
||||||
|
|
||||||
cmark_llist_free_full(row->cells, (cmark_free_func) free_table_cell);
|
|
||||||
|
|
||||||
free(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cmark_strbuf *unescape_pipes(cmark_mem *mem, unsigned char *string, bufsize_t len)
|
|
||||||
{
|
|
||||||
cmark_strbuf *res = (cmark_strbuf *)malloc(sizeof(cmark_strbuf));
|
|
||||||
bufsize_t r, w;
|
|
||||||
|
|
||||||
cmark_strbuf_init(mem, res, len + 1);
|
|
||||||
cmark_strbuf_put(res, string, len);
|
|
||||||
cmark_strbuf_putc(res, '\0');
|
|
||||||
|
|
||||||
for (r = 0, w = 0; r < len; ++r) {
|
|
||||||
if (res->ptr[r] == '\\' && res->ptr[r + 1] == '|')
|
|
||||||
r++;
|
|
||||||
|
|
||||||
res->ptr[w++] = res->ptr[r];
|
|
||||||
}
|
|
||||||
|
|
||||||
cmark_strbuf_truncate(res, w);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static table_row *row_from_string(cmark_mem *mem, unsigned char *string, int len) {
|
|
||||||
table_row *row = NULL;
|
|
||||||
bufsize_t cell_matched = 0;
|
|
||||||
bufsize_t cell_offset = 0;
|
|
||||||
|
|
||||||
row = malloc(sizeof(table_row));
|
|
||||||
row->n_columns = 0;
|
|
||||||
row->cells = NULL;
|
|
||||||
|
|
||||||
do {
|
|
||||||
cell_matched = scan_table_cell(string, len, cell_offset);
|
|
||||||
if (cell_matched) {
|
|
||||||
cmark_strbuf *cell_buf = unescape_pipes(mem, string + cell_offset + 1,
|
|
||||||
cell_matched - 1);
|
|
||||||
row->n_columns += 1;
|
|
||||||
row->cells = cmark_llist_append(row->cells, cell_buf);
|
|
||||||
}
|
|
||||||
cell_offset += cell_matched;
|
|
||||||
} while (cell_matched);
|
|
||||||
|
|
||||||
cell_matched = scan_table_row_end(string, len, cell_offset);
|
|
||||||
cell_offset += cell_matched;
|
|
||||||
|
|
||||||
if (!cell_matched || cell_offset != len) {
|
|
||||||
free_table_row(row);
|
|
||||||
row = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
|
|
||||||
cmark_parser * parser,
|
|
||||||
cmark_node * parent_container,
|
|
||||||
unsigned char * input,
|
|
||||||
int len) {
|
|
||||||
bufsize_t matched = scan_table_start(input, len, cmark_parser_get_first_nonspace(parser));
|
|
||||||
cmark_node *table_header;
|
|
||||||
table_row *header_row = NULL;
|
|
||||||
table_row *marker_row = NULL;
|
|
||||||
const char *parent_string;
|
|
||||||
|
|
||||||
if (!matched)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
parent_string = cmark_node_get_string_content(parent_container);
|
|
||||||
|
|
||||||
header_row = row_from_string(parser->mem, (unsigned char *) parent_string, strlen(parent_string));
|
|
||||||
|
|
||||||
if (!header_row) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
marker_row = row_from_string(parser->mem, input + cmark_parser_get_first_nonspace(parser),
|
|
||||||
len - cmark_parser_get_first_nonspace(parser));
|
|
||||||
|
|
||||||
assert(marker_row);
|
|
||||||
|
|
||||||
if (header_row->n_columns != marker_row->n_columns) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cmark_node_set_type(parent_container, CMARK_NODE_TABLE)) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmark_node_set_syntax_extension(parent_container, self);
|
|
||||||
cmark_node_set_n_table_columns(parent_container, header_row->n_columns);
|
|
||||||
|
|
||||||
table_header = cmark_parser_add_child(parser, parent_container,
|
|
||||||
CMARK_NODE_TABLE_ROW, cmark_parser_get_offset(parser));
|
|
||||||
cmark_node_set_syntax_extension(table_header, self);
|
|
||||||
cmark_node_set_is_table_header(table_header, true);
|
|
||||||
|
|
||||||
{
|
|
||||||
cmark_llist *tmp;
|
|
||||||
|
|
||||||
for (tmp = header_row->cells; tmp; tmp = tmp->next) {
|
|
||||||
cmark_strbuf *cell_buf = (cmark_strbuf *) tmp->data;
|
|
||||||
cmark_node *header_cell = cmark_parser_add_child(parser, table_header,
|
|
||||||
CMARK_NODE_TABLE_CELL, cmark_parser_get_offset(parser));
|
|
||||||
cmark_node_set_string_content(header_cell, (char *) cell_buf->ptr);
|
|
||||||
cmark_node_set_syntax_extension(header_cell, self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmark_parser_advance_offset(parser, input,
|
|
||||||
strlen(input) - 1 - cmark_parser_get_offset(parser),
|
|
||||||
false);
|
|
||||||
done:
|
|
||||||
free_table_row(header_row);
|
|
||||||
free_table_row(marker_row);
|
|
||||||
return parent_container;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cmark_node *try_opening_table_row(cmark_syntax_extension *self,
|
|
||||||
cmark_parser * parser,
|
|
||||||
cmark_node * parent_container,
|
|
||||||
unsigned char * input,
|
|
||||||
int len) {
|
|
||||||
cmark_node *table_row_block;
|
|
||||||
table_row *row;
|
|
||||||
|
|
||||||
if (cmark_parser_is_blank(parser))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
table_row_block = cmark_parser_add_child(parser, parent_container,
|
|
||||||
CMARK_NODE_TABLE_ROW, cmark_parser_get_offset(parser));
|
|
||||||
|
|
||||||
cmark_node_set_syntax_extension(table_row_block, self);
|
|
||||||
|
|
||||||
/* We don't advance the offset here */
|
|
||||||
|
|
||||||
row = row_from_string(parser->mem, input + cmark_parser_get_first_nonspace(parser),
|
|
||||||
len - cmark_parser_get_first_nonspace(parser));
|
|
||||||
|
|
||||||
{
|
|
||||||
cmark_llist *tmp;
|
|
||||||
|
|
||||||
for (tmp = row->cells; tmp; tmp = tmp->next) {
|
|
||||||
cmark_strbuf *cell_buf = (cmark_strbuf *) tmp->data;
|
|
||||||
cmark_node *cell = cmark_parser_add_child(parser, table_row_block,
|
|
||||||
CMARK_NODE_TABLE_CELL, cmark_parser_get_offset(parser));
|
|
||||||
cmark_node_set_string_content(cell, (char *) cell_buf->ptr);
|
|
||||||
cmark_node_set_syntax_extension(cell, self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free_table_row(row);
|
|
||||||
|
|
||||||
cmark_parser_advance_offset(parser, input,
|
|
||||||
len - 1 - cmark_parser_get_offset(parser),
|
|
||||||
false);
|
|
||||||
|
|
||||||
return table_row_block;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cmark_node *try_opening_table_block(cmark_syntax_extension * syntax_extension,
|
|
||||||
int indented,
|
|
||||||
cmark_parser * parser,
|
|
||||||
cmark_node * parent_container,
|
|
||||||
unsigned char * input,
|
|
||||||
int len) {
|
|
||||||
cmark_node_type parent_type = cmark_node_get_type(parent_container);
|
|
||||||
|
|
||||||
if (!indented && parent_type == CMARK_NODE_PARAGRAPH) {
|
|
||||||
return try_opening_table_header(syntax_extension, parser, parent_container, input, len);
|
|
||||||
} else if (!indented && parent_type == CMARK_NODE_TABLE) {
|
|
||||||
return try_opening_table_row(syntax_extension, parser, parent_container, input, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int table_matches(cmark_syntax_extension *self,
|
|
||||||
cmark_parser * parser,
|
|
||||||
unsigned char * input,
|
|
||||||
int len,
|
|
||||||
cmark_node * parent_container) {
|
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
if (cmark_node_get_type(parent_container) == CMARK_NODE_TABLE) {
|
|
||||||
table_row *new_row = row_from_string(parser->mem, input + cmark_parser_get_first_nonspace(parser),
|
|
||||||
len - cmark_parser_get_first_nonspace(parser));
|
|
||||||
if (new_row) {
|
|
||||||
if (new_row->n_columns == cmark_node_get_n_table_columns(parent_container))
|
|
||||||
res = 1;
|
|
||||||
}
|
|
||||||
free_table_row(new_row);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cmark_syntax_extension *register_table_syntax_extension(void) {
|
|
||||||
cmark_syntax_extension *ext = cmark_syntax_extension_new("piped-tables");
|
|
||||||
|
|
||||||
cmark_syntax_extension_set_match_block_func(ext, table_matches);
|
|
||||||
cmark_syntax_extension_set_open_block_func(ext, try_opening_table_block);
|
|
||||||
|
|
||||||
return ext;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cmark_node *strikethrough_match(cmark_syntax_extension *self,
|
|
||||||
cmark_parser *parser,
|
|
||||||
cmark_node *parent,
|
|
||||||
unsigned char character,
|
|
||||||
cmark_inline_parser *inline_parser)
|
|
||||||
{
|
|
||||||
cmark_node *res = NULL;
|
|
||||||
int left_flanking, right_flanking, punct_before, punct_after;
|
|
||||||
int num_delims;
|
|
||||||
|
|
||||||
/* Exit early */
|
|
||||||
if (character != '~')
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
num_delims = cmark_inline_parser_scan_delimiters(inline_parser, 1, '~',
|
|
||||||
&left_flanking, &right_flanking, &punct_before, &punct_after);
|
|
||||||
|
|
||||||
if (num_delims > 0) { /* Should not be needed */
|
|
||||||
int can_open, can_close;
|
|
||||||
|
|
||||||
res = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
|
|
||||||
cmark_node_set_literal(res, "~");
|
|
||||||
|
|
||||||
can_open = left_flanking;
|
|
||||||
can_close = right_flanking;
|
|
||||||
if (can_open || can_close)
|
|
||||||
cmark_inline_parser_push_delimiter(inline_parser, character, can_open, can_close, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static delimiter *strikethrough_insert(cmark_syntax_extension *self,
|
|
||||||
cmark_parser *parser,
|
|
||||||
cmark_inline_parser *inline_parser,
|
|
||||||
delimiter *opener,
|
|
||||||
delimiter *closer)
|
|
||||||
{
|
|
||||||
cmark_node *strikethrough;
|
|
||||||
cmark_node *tmp, *next;
|
|
||||||
delimiter *delim, *tmp_delim;
|
|
||||||
delimiter *res = closer->next;
|
|
||||||
|
|
||||||
strikethrough = opener->inl_text;
|
|
||||||
|
|
||||||
if (!cmark_node_set_type(strikethrough, CMARK_NODE_STRIKETHROUGH))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
cmark_node_set_string_content(strikethrough, "~");
|
|
||||||
tmp = cmark_node_next(opener->inl_text);
|
|
||||||
|
|
||||||
while (tmp) {
|
|
||||||
if (tmp == closer->inl_text)
|
|
||||||
break;
|
|
||||||
next = cmark_node_next(tmp);
|
|
||||||
cmark_node_append_child(strikethrough, tmp);
|
|
||||||
tmp = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmark_node_free(closer->inl_text);
|
|
||||||
|
|
||||||
delim = closer;
|
|
||||||
while (delim != NULL && delim != opener) {
|
|
||||||
tmp_delim = delim->previous;
|
|
||||||
cmark_inline_parser_remove_delimiter(inline_parser, delim);
|
|
||||||
delim = tmp_delim;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmark_inline_parser_remove_delimiter(inline_parser, opener);
|
|
||||||
|
|
||||||
done:
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cmark_syntax_extension *create_strikethrough_extension(void) {
|
|
||||||
cmark_syntax_extension *ext = cmark_syntax_extension_new("tilde_strikethrough");
|
|
||||||
cmark_llist *special_chars = NULL;
|
|
||||||
|
|
||||||
cmark_syntax_extension_set_match_inline_func(ext, strikethrough_match);
|
|
||||||
cmark_syntax_extension_set_inline_from_delim_func(ext, strikethrough_insert);
|
|
||||||
special_chars = cmark_llist_append(special_chars, (void *) '~');
|
|
||||||
cmark_syntax_extension_set_special_inline_chars(ext, special_chars);
|
|
||||||
|
|
||||||
return ext;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_libcmarkextensions(cmark_plugin *plugin) {
|
|
||||||
cmark_plugin_register_syntax_extension(plugin, register_table_syntax_extension());
|
|
||||||
cmark_plugin_register_syntax_extension(plugin, create_strikethrough_extension());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef CORE_EXTENSIONS_H
|
||||||
|
#define CORE_EXTENSIONS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cmark_extension_api.h>
|
||||||
|
|
||||||
|
int core_extensions_registration(cmark_plugin *plugin);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,585 +0,0 @@
|
||||||
/* Generated by re2c 0.16 */
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "ext_scanners.h"
|
|
||||||
|
|
||||||
bufsize_t _ext_scan_at(bufsize_t (*scanner)(const unsigned char *),
|
|
||||||
unsigned char *ptr, int len, bufsize_t offset) {
|
|
||||||
bufsize_t res;
|
|
||||||
|
|
||||||
if (ptr == NULL || offset > len) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
unsigned char lim = ptr[len];
|
|
||||||
|
|
||||||
ptr[len] = '\0';
|
|
||||||
res = scanner(ptr + offset);
|
|
||||||
ptr[len] = lim;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufsize_t _scan_table_cell(const unsigned char *p) {
|
|
||||||
const unsigned char *marker = NULL;
|
|
||||||
const unsigned char *start = p;
|
|
||||||
|
|
||||||
{
|
|
||||||
unsigned char yych;
|
|
||||||
unsigned int yyaccept = 0;
|
|
||||||
static const unsigned char yybm[] = {
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 0, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
|
||||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64,
|
|
||||||
64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0,
|
|
||||||
};
|
|
||||||
yych = *(marker = p);
|
|
||||||
if (yych <= 0xDF) {
|
|
||||||
if (yych <= '{') {
|
|
||||||
if (yych != '\n')
|
|
||||||
goto yy3;
|
|
||||||
} else {
|
|
||||||
if (yych <= '|')
|
|
||||||
goto yy4;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy3;
|
|
||||||
if (yych >= 0xC2)
|
|
||||||
goto yy5;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xEF) {
|
|
||||||
if (yych <= 0xE0)
|
|
||||||
goto yy7;
|
|
||||||
if (yych == 0xED)
|
|
||||||
goto yy9;
|
|
||||||
goto yy8;
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xF0)
|
|
||||||
goto yy10;
|
|
||||||
if (yych <= 0xF3)
|
|
||||||
goto yy11;
|
|
||||||
if (yych <= 0xF4)
|
|
||||||
goto yy12;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yy2 : { return 0; }
|
|
||||||
yy3:
|
|
||||||
yych = *++p;
|
|
||||||
goto yy2;
|
|
||||||
yy4:
|
|
||||||
yyaccept = 0;
|
|
||||||
yych = *(marker = ++p);
|
|
||||||
if (yych <= '{') {
|
|
||||||
if (yych <= '\n') {
|
|
||||||
if (yych <= '\t')
|
|
||||||
goto yy14;
|
|
||||||
goto yy2;
|
|
||||||
} else {
|
|
||||||
if (yych == '\r')
|
|
||||||
goto yy2;
|
|
||||||
goto yy14;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (yych <= 0x7F) {
|
|
||||||
if (yych <= '|')
|
|
||||||
goto yy2;
|
|
||||||
goto yy14;
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xC1)
|
|
||||||
goto yy2;
|
|
||||||
if (yych <= 0xF4)
|
|
||||||
goto yy14;
|
|
||||||
goto yy2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yy5:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy3;
|
|
||||||
yy6:
|
|
||||||
p = marker;
|
|
||||||
if (yyaccept == 0) {
|
|
||||||
goto yy2;
|
|
||||||
} else {
|
|
||||||
goto yy15;
|
|
||||||
}
|
|
||||||
yy7:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x9F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy5;
|
|
||||||
goto yy6;
|
|
||||||
yy8:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy5;
|
|
||||||
goto yy6;
|
|
||||||
yy9:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0x9F)
|
|
||||||
goto yy5;
|
|
||||||
goto yy6;
|
|
||||||
yy10:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x8F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy8;
|
|
||||||
goto yy6;
|
|
||||||
yy11:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy8;
|
|
||||||
goto yy6;
|
|
||||||
yy12:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0x8F)
|
|
||||||
goto yy8;
|
|
||||||
goto yy6;
|
|
||||||
yy13:
|
|
||||||
yyaccept = 1;
|
|
||||||
marker = ++p;
|
|
||||||
yych = *p;
|
|
||||||
yy14:
|
|
||||||
if (yybm[0 + yych] & 64) {
|
|
||||||
goto yy13;
|
|
||||||
}
|
|
||||||
if (yych <= 0xEC) {
|
|
||||||
if (yych <= 0xC1) {
|
|
||||||
if (yych <= '\r')
|
|
||||||
goto yy15;
|
|
||||||
if (yych <= '\\')
|
|
||||||
goto yy16;
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xDF)
|
|
||||||
goto yy18;
|
|
||||||
if (yych <= 0xE0)
|
|
||||||
goto yy19;
|
|
||||||
goto yy20;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xF0) {
|
|
||||||
if (yych <= 0xED)
|
|
||||||
goto yy21;
|
|
||||||
if (yych <= 0xEF)
|
|
||||||
goto yy20;
|
|
||||||
goto yy22;
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xF3)
|
|
||||||
goto yy23;
|
|
||||||
if (yych <= 0xF4)
|
|
||||||
goto yy24;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yy15 : { return (bufsize_t)(p - start); }
|
|
||||||
yy16:
|
|
||||||
yyaccept = 1;
|
|
||||||
marker = ++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yybm[0 + yych] & 128) {
|
|
||||||
goto yy16;
|
|
||||||
}
|
|
||||||
if (yych <= 0xDF) {
|
|
||||||
if (yych <= '\f') {
|
|
||||||
if (yych == '\n')
|
|
||||||
goto yy15;
|
|
||||||
goto yy13;
|
|
||||||
} else {
|
|
||||||
if (yych <= '\r')
|
|
||||||
goto yy15;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy13;
|
|
||||||
if (yych <= 0xC1)
|
|
||||||
goto yy15;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xEF) {
|
|
||||||
if (yych <= 0xE0)
|
|
||||||
goto yy19;
|
|
||||||
if (yych == 0xED)
|
|
||||||
goto yy21;
|
|
||||||
goto yy20;
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xF0)
|
|
||||||
goto yy22;
|
|
||||||
if (yych <= 0xF3)
|
|
||||||
goto yy23;
|
|
||||||
if (yych <= 0xF4)
|
|
||||||
goto yy24;
|
|
||||||
goto yy15;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yy18:
|
|
||||||
++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy13;
|
|
||||||
goto yy6;
|
|
||||||
yy19:
|
|
||||||
++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yych <= 0x9F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy18;
|
|
||||||
goto yy6;
|
|
||||||
yy20:
|
|
||||||
++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy18;
|
|
||||||
goto yy6;
|
|
||||||
yy21:
|
|
||||||
++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0x9F)
|
|
||||||
goto yy18;
|
|
||||||
goto yy6;
|
|
||||||
yy22:
|
|
||||||
++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yych <= 0x8F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy20;
|
|
||||||
goto yy6;
|
|
||||||
yy23:
|
|
||||||
++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy20;
|
|
||||||
goto yy6;
|
|
||||||
yy24:
|
|
||||||
++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy6;
|
|
||||||
if (yych <= 0x8F)
|
|
||||||
goto yy20;
|
|
||||||
goto yy6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bufsize_t _scan_table_row_end(const unsigned char *p) {
|
|
||||||
const unsigned char *marker = NULL;
|
|
||||||
const unsigned char *start = p;
|
|
||||||
|
|
||||||
{
|
|
||||||
unsigned char yych;
|
|
||||||
yych = *(marker = p);
|
|
||||||
if (yych <= 0xDF) {
|
|
||||||
if (yych <= '{') {
|
|
||||||
if (yych != '\n')
|
|
||||||
goto yy28;
|
|
||||||
} else {
|
|
||||||
if (yych <= '|')
|
|
||||||
goto yy29;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy28;
|
|
||||||
if (yych >= 0xC2)
|
|
||||||
goto yy30;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xEF) {
|
|
||||||
if (yych <= 0xE0)
|
|
||||||
goto yy32;
|
|
||||||
if (yych == 0xED)
|
|
||||||
goto yy34;
|
|
||||||
goto yy33;
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xF0)
|
|
||||||
goto yy35;
|
|
||||||
if (yych <= 0xF3)
|
|
||||||
goto yy36;
|
|
||||||
if (yych <= 0xF4)
|
|
||||||
goto yy37;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yy27 : { return 0; }
|
|
||||||
yy28:
|
|
||||||
yych = *++p;
|
|
||||||
goto yy27;
|
|
||||||
yy29:
|
|
||||||
yych = *(marker = ++p);
|
|
||||||
if (yych == '\n')
|
|
||||||
goto yy38;
|
|
||||||
if (yych == '\r')
|
|
||||||
goto yy40;
|
|
||||||
goto yy27;
|
|
||||||
yy30:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy31;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy28;
|
|
||||||
yy31:
|
|
||||||
p = marker;
|
|
||||||
goto yy27;
|
|
||||||
yy32:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x9F)
|
|
||||||
goto yy31;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy30;
|
|
||||||
goto yy31;
|
|
||||||
yy33:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy31;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy30;
|
|
||||||
goto yy31;
|
|
||||||
yy34:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy31;
|
|
||||||
if (yych <= 0x9F)
|
|
||||||
goto yy30;
|
|
||||||
goto yy31;
|
|
||||||
yy35:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x8F)
|
|
||||||
goto yy31;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy33;
|
|
||||||
goto yy31;
|
|
||||||
yy36:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy31;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy33;
|
|
||||||
goto yy31;
|
|
||||||
yy37:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy31;
|
|
||||||
if (yych <= 0x8F)
|
|
||||||
goto yy33;
|
|
||||||
goto yy31;
|
|
||||||
yy38:
|
|
||||||
++p;
|
|
||||||
{ return (bufsize_t)(p - start); }
|
|
||||||
yy40:
|
|
||||||
++p;
|
|
||||||
if ((yych = *p) == '\n')
|
|
||||||
goto yy38;
|
|
||||||
goto yy31;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bufsize_t _scan_table_start(const unsigned char *p) {
|
|
||||||
const unsigned char *marker = NULL;
|
|
||||||
const unsigned char *start = p;
|
|
||||||
|
|
||||||
{
|
|
||||||
unsigned char yych;
|
|
||||||
static const unsigned char yybm[] = {
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
};
|
|
||||||
yych = *(marker = p);
|
|
||||||
if (yych <= 0xDF) {
|
|
||||||
if (yych <= '{') {
|
|
||||||
if (yych != '\n')
|
|
||||||
goto yy44;
|
|
||||||
} else {
|
|
||||||
if (yych <= '|')
|
|
||||||
goto yy45;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy44;
|
|
||||||
if (yych >= 0xC2)
|
|
||||||
goto yy46;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xEF) {
|
|
||||||
if (yych <= 0xE0)
|
|
||||||
goto yy48;
|
|
||||||
if (yych == 0xED)
|
|
||||||
goto yy50;
|
|
||||||
goto yy49;
|
|
||||||
} else {
|
|
||||||
if (yych <= 0xF0)
|
|
||||||
goto yy51;
|
|
||||||
if (yych <= 0xF3)
|
|
||||||
goto yy52;
|
|
||||||
if (yych <= 0xF4)
|
|
||||||
goto yy53;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yy43 : { return 0; }
|
|
||||||
yy44:
|
|
||||||
yych = *++p;
|
|
||||||
goto yy43;
|
|
||||||
yy45:
|
|
||||||
yych = *(marker = ++p);
|
|
||||||
if (yybm[0 + yych] & 64) {
|
|
||||||
goto yy54;
|
|
||||||
}
|
|
||||||
if (yych == '-')
|
|
||||||
goto yy56;
|
|
||||||
goto yy43;
|
|
||||||
yy46:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy47;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy44;
|
|
||||||
yy47:
|
|
||||||
p = marker;
|
|
||||||
goto yy43;
|
|
||||||
yy48:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x9F)
|
|
||||||
goto yy47;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy46;
|
|
||||||
goto yy47;
|
|
||||||
yy49:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy47;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy46;
|
|
||||||
goto yy47;
|
|
||||||
yy50:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy47;
|
|
||||||
if (yych <= 0x9F)
|
|
||||||
goto yy46;
|
|
||||||
goto yy47;
|
|
||||||
yy51:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x8F)
|
|
||||||
goto yy47;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy49;
|
|
||||||
goto yy47;
|
|
||||||
yy52:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy47;
|
|
||||||
if (yych <= 0xBF)
|
|
||||||
goto yy49;
|
|
||||||
goto yy47;
|
|
||||||
yy53:
|
|
||||||
yych = *++p;
|
|
||||||
if (yych <= 0x7F)
|
|
||||||
goto yy47;
|
|
||||||
if (yych <= 0x8F)
|
|
||||||
goto yy49;
|
|
||||||
goto yy47;
|
|
||||||
yy54:
|
|
||||||
++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yybm[0 + yych] & 64) {
|
|
||||||
goto yy54;
|
|
||||||
}
|
|
||||||
if (yych != '-')
|
|
||||||
goto yy47;
|
|
||||||
yy56:
|
|
||||||
++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yybm[0 + yych] & 128) {
|
|
||||||
goto yy56;
|
|
||||||
}
|
|
||||||
if (yych <= '\f') {
|
|
||||||
if (yych == '\t')
|
|
||||||
goto yy58;
|
|
||||||
if (yych <= '\n')
|
|
||||||
goto yy47;
|
|
||||||
} else {
|
|
||||||
if (yych <= ' ') {
|
|
||||||
if (yych <= 0x1F)
|
|
||||||
goto yy47;
|
|
||||||
} else {
|
|
||||||
if (yych == '|')
|
|
||||||
goto yy60;
|
|
||||||
goto yy47;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yy58:
|
|
||||||
++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yych <= '\f') {
|
|
||||||
if (yych == '\t')
|
|
||||||
goto yy58;
|
|
||||||
if (yych <= '\n')
|
|
||||||
goto yy47;
|
|
||||||
goto yy58;
|
|
||||||
} else {
|
|
||||||
if (yych <= ' ') {
|
|
||||||
if (yych <= 0x1F)
|
|
||||||
goto yy47;
|
|
||||||
goto yy58;
|
|
||||||
} else {
|
|
||||||
if (yych != '|')
|
|
||||||
goto yy47;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yy60:
|
|
||||||
++p;
|
|
||||||
yych = *p;
|
|
||||||
if (yybm[0 + yych] & 64) {
|
|
||||||
goto yy54;
|
|
||||||
}
|
|
||||||
if (yych <= '\r') {
|
|
||||||
if (yych <= 0x08)
|
|
||||||
goto yy47;
|
|
||||||
if (yych >= '\v')
|
|
||||||
goto yy63;
|
|
||||||
} else {
|
|
||||||
if (yych == '-')
|
|
||||||
goto yy56;
|
|
||||||
goto yy47;
|
|
||||||
}
|
|
||||||
yy61:
|
|
||||||
++p;
|
|
||||||
{ return (bufsize_t)(p - start); }
|
|
||||||
yy63:
|
|
||||||
++p;
|
|
||||||
if ((yych = *p) == '\n')
|
|
||||||
goto yy61;
|
|
||||||
goto yy47;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
#include "cmark.h"
|
|
||||||
#include "chunk.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bufsize_t _ext_scan_at(bufsize_t (*scanner)(const unsigned char *), unsigned char *ptr,
|
|
||||||
int len, bufsize_t offset);
|
|
||||||
bufsize_t _scan_table_start(const unsigned char *p);
|
|
||||||
bufsize_t _scan_table_cell(const unsigned char *p);
|
|
||||||
bufsize_t _scan_table_row_end(const unsigned char *p);
|
|
||||||
|
|
||||||
#define scan_table_start(c, l, n) _ext_scan_at(&_scan_table_start, c, l, n)
|
|
||||||
#define scan_table_cell(c, l, n) _ext_scan_at(&_scan_table_cell, c, l, n)
|
|
||||||
#define scan_table_row_end(c, l, n) _ext_scan_at(&_scan_table_row_end, c, l, n)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,65 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include "ext_scanners.h"
|
|
||||||
|
|
||||||
bufsize_t _ext_scan_at(bufsize_t (*scanner)(const unsigned char *), unsigned char *ptr, int len, bufsize_t offset)
|
|
||||||
{
|
|
||||||
bufsize_t res;
|
|
||||||
|
|
||||||
if (ptr == NULL || offset > len) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
unsigned char lim = ptr[len];
|
|
||||||
|
|
||||||
ptr[len] = '\0';
|
|
||||||
res = scanner(ptr + offset);
|
|
||||||
ptr[len] = lim;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!re2c
|
|
||||||
re2c:define:YYCTYPE = "unsigned char";
|
|
||||||
re2c:define:YYCURSOR = p;
|
|
||||||
re2c:define:YYMARKER = marker;
|
|
||||||
re2c:define:YYCTXMARKER = marker;
|
|
||||||
re2c:yyfill:enable = 0;
|
|
||||||
|
|
||||||
spacechar = [ \t\v\f];
|
|
||||||
newline = [\r]?[\n];
|
|
||||||
|
|
||||||
escaped_char = [\\][|!"#$%&'()*+,./:;<=>?@[\\\]^_`{}~-];
|
|
||||||
|
|
||||||
table_marker = [|](spacechar*[-]+spacechar*);
|
|
||||||
table_cell = [|](escaped_char|[^|\r\n])+;
|
|
||||||
*/
|
|
||||||
|
|
||||||
bufsize_t _scan_table_cell(const unsigned char *p)
|
|
||||||
{
|
|
||||||
const unsigned char *marker = NULL;
|
|
||||||
const unsigned char *start = p;
|
|
||||||
/*!re2c
|
|
||||||
table_cell { return (bufsize_t)(p - start); }
|
|
||||||
.? { return 0; }
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
bufsize_t _scan_table_row_end(const unsigned char *p)
|
|
||||||
{
|
|
||||||
const unsigned char *marker = NULL;
|
|
||||||
const unsigned char *start = p;
|
|
||||||
/*!re2c
|
|
||||||
[|]newline { return (bufsize_t)(p - start); }
|
|
||||||
.? { return 0; }
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
bufsize_t _scan_table_start(const unsigned char *p)
|
|
||||||
{
|
|
||||||
const unsigned char *marker = NULL;
|
|
||||||
const unsigned char *start = p;
|
|
||||||
/*!re2c
|
|
||||||
(table_marker)+ [|]newline { return (bufsize_t)(p - start); }
|
|
||||||
.? { return 0; }
|
|
||||||
*/
|
|
||||||
}
|
|
|
@ -27,37 +27,31 @@ Node Structure
|
||||||
.RS 0n
|
.RS 0n
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* Error status */
|
/* Error status */
|
||||||
CMARK_NODE_NONE,
|
CMARK_NODE_NONE = 0x0000,
|
||||||
|
|
||||||
/* Block */
|
/* Block */
|
||||||
CMARK_NODE_DOCUMENT,
|
CMARK_NODE_DOCUMENT = CMARK_NODE_TYPE_BLOCK | 0x0001,
|
||||||
CMARK_NODE_BLOCK_QUOTE,
|
CMARK_NODE_BLOCK_QUOTE = CMARK_NODE_TYPE_BLOCK | 0x0002,
|
||||||
CMARK_NODE_LIST,
|
CMARK_NODE_LIST = CMARK_NODE_TYPE_BLOCK | 0x0003,
|
||||||
CMARK_NODE_ITEM,
|
CMARK_NODE_ITEM = CMARK_NODE_TYPE_BLOCK | 0x0004,
|
||||||
CMARK_NODE_CODE_BLOCK,
|
CMARK_NODE_CODE_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0005,
|
||||||
CMARK_NODE_HTML_BLOCK,
|
CMARK_NODE_HTML_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0006,
|
||||||
CMARK_NODE_CUSTOM_BLOCK,
|
CMARK_NODE_CUSTOM_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0007,
|
||||||
CMARK_NODE_PARAGRAPH,
|
CMARK_NODE_PARAGRAPH = CMARK_NODE_TYPE_BLOCK | 0x0008,
|
||||||
CMARK_NODE_HEADING,
|
CMARK_NODE_HEADING = CMARK_NODE_TYPE_BLOCK | 0x0009,
|
||||||
CMARK_NODE_THEMATIC_BREAK,
|
CMARK_NODE_THEMATIC_BREAK = CMARK_NODE_TYPE_BLOCK | 0x000a,
|
||||||
|
|
||||||
CMARK_NODE_FIRST_BLOCK = CMARK_NODE_DOCUMENT,
|
|
||||||
CMARK_NODE_LAST_BLOCK = CMARK_NODE_THEMATIC_BREAK,
|
|
||||||
|
|
||||||
/* Inline */
|
/* Inline */
|
||||||
CMARK_NODE_TEXT,
|
CMARK_NODE_TEXT = CMARK_NODE_TYPE_INLINE | 0x0001,
|
||||||
CMARK_NODE_SOFTBREAK,
|
CMARK_NODE_SOFTBREAK = CMARK_NODE_TYPE_INLINE | 0x0002,
|
||||||
CMARK_NODE_LINEBREAK,
|
CMARK_NODE_LINEBREAK = CMARK_NODE_TYPE_INLINE | 0x0003,
|
||||||
CMARK_NODE_CODE,
|
CMARK_NODE_CODE = CMARK_NODE_TYPE_INLINE | 0x0004,
|
||||||
CMARK_NODE_HTML_INLINE,
|
CMARK_NODE_HTML_INLINE = CMARK_NODE_TYPE_INLINE | 0x0005,
|
||||||
CMARK_NODE_CUSTOM_INLINE,
|
CMARK_NODE_CUSTOM_INLINE = CMARK_NODE_TYPE_INLINE | 0x0006,
|
||||||
CMARK_NODE_EMPH,
|
CMARK_NODE_EMPH = CMARK_NODE_TYPE_INLINE | 0x0007,
|
||||||
CMARK_NODE_STRONG,
|
CMARK_NODE_STRONG = CMARK_NODE_TYPE_INLINE | 0x0008,
|
||||||
CMARK_NODE_LINK,
|
CMARK_NODE_LINK = CMARK_NODE_TYPE_INLINE | 0x0009,
|
||||||
CMARK_NODE_IMAGE,
|
CMARK_NODE_IMAGE = CMARK_NODE_TYPE_INLINE | 0x000a,
|
||||||
|
|
||||||
CMARK_NODE_FIRST_INLINE = CMARK_NODE_TEXT,
|
|
||||||
CMARK_NODE_LAST_INLINE = CMARK_NODE_IMAGE,
|
|
||||||
} cmark_node_type;
|
} cmark_node_type;
|
||||||
.RE
|
.RE
|
||||||
\f[]
|
\f[]
|
||||||
|
|
|
@ -54,7 +54,6 @@ set(LIBRARY_SOURCES
|
||||||
|
|
||||||
set(PROGRAM "cmark")
|
set(PROGRAM "cmark")
|
||||||
set(PROGRAM_SOURCES
|
set(PROGRAM_SOURCES
|
||||||
${LIBRARY_SOURCES}
|
|
||||||
main.c
|
main.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -68,6 +67,11 @@ include (GenerateExportHeader)
|
||||||
add_executable(${PROGRAM} ${PROGRAM_SOURCES})
|
add_executable(${PROGRAM} ${PROGRAM_SOURCES})
|
||||||
add_compiler_export_flags()
|
add_compiler_export_flags()
|
||||||
|
|
||||||
|
target_link_libraries(${PROGRAM} libcmark)
|
||||||
|
|
||||||
|
add_dependencies(${PROGRAM} libcmarkextensions_static)
|
||||||
|
target_link_libraries(${PROGRAM} libcmarkextensions_static)
|
||||||
|
|
||||||
# Disable the PUBLIC declarations when compiling the executable:
|
# Disable the PUBLIC declarations when compiling the executable:
|
||||||
set_target_properties(${PROGRAM} PROPERTIES
|
set_target_properties(${PROGRAM} PROPERTIES
|
||||||
COMPILE_FLAGS -DCMARK_STATIC_DEFINE)
|
COMPILE_FLAGS -DCMARK_STATIC_DEFINE)
|
||||||
|
@ -197,7 +201,7 @@ if(MSVC)
|
||||||
endif()
|
endif()
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4706 /D_CRT_SECURE_NO_WARNINGS")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4706 /D_CRT_SECURE_NO_WARNINGS")
|
||||||
elseif(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
elseif(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -std=c99 -pedantic")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -std=c99 -pedantic")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Compile as C++ under MSVC older than 12.0
|
# Compile as C++ under MSVC older than 12.0
|
||||||
|
|
60
src/blocks.c
60
src/blocks.c
|
@ -82,11 +82,11 @@ static cmark_node *make_document(cmark_mem *mem) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmark_parser_attach_syntax_extension(cmark_parser *parser,
|
int cmark_parser_attach_syntax_extension(cmark_parser *parser,
|
||||||
cmark_syntax_extension *extension) {
|
cmark_syntax_extension *extension) {
|
||||||
parser->syntax_extensions = cmark_llist_append(parser->syntax_extensions, extension);
|
parser->syntax_extensions = cmark_llist_append(parser->mem, parser->syntax_extensions, extension);
|
||||||
if (extension->match_inline && extension->insert_inline_from_delim) {
|
if (extension->match_inline || extension->insert_inline_from_delim) {
|
||||||
parser->inline_syntax_extensions = cmark_llist_append(
|
parser->inline_syntax_extensions = cmark_llist_append(
|
||||||
parser->inline_syntax_extensions, extension);
|
parser->mem, parser->inline_syntax_extensions, extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -145,8 +145,8 @@ void cmark_parser_free(cmark_parser *parser) {
|
||||||
cmark_parser_dispose(parser);
|
cmark_parser_dispose(parser);
|
||||||
cmark_strbuf_free(&parser->curline);
|
cmark_strbuf_free(&parser->curline);
|
||||||
cmark_strbuf_free(&parser->linebuf);
|
cmark_strbuf_free(&parser->linebuf);
|
||||||
cmark_llist_free(parser->syntax_extensions);
|
cmark_llist_free(parser->mem, parser->syntax_extensions);
|
||||||
cmark_llist_free(parser->inline_syntax_extensions);
|
cmark_llist_free(parser->mem, parser->inline_syntax_extensions);
|
||||||
mem->free(parser);
|
mem->free(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,31 +173,19 @@ static bool is_blank(cmark_strbuf *s, bufsize_t offset) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CMARK_INLINE bool can_contain(cmark_node_type parent_type,
|
|
||||||
cmark_node_type child_type) {
|
|
||||||
if (parent_type == CMARK_NODE_TABLE) {
|
|
||||||
return child_type == CMARK_NODE_TABLE_ROW;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent_type == CMARK_NODE_TABLE_ROW)
|
|
||||||
return child_type == CMARK_NODE_TABLE_CELL;
|
|
||||||
|
|
||||||
return (parent_type == CMARK_NODE_DOCUMENT ||
|
|
||||||
parent_type == CMARK_NODE_BLOCK_QUOTE ||
|
|
||||||
parent_type == CMARK_NODE_ITEM ||
|
|
||||||
(parent_type == CMARK_NODE_LIST && child_type == CMARK_NODE_ITEM));
|
|
||||||
}
|
|
||||||
|
|
||||||
static CMARK_INLINE bool accepts_lines(cmark_node_type block_type) {
|
static CMARK_INLINE bool accepts_lines(cmark_node_type block_type) {
|
||||||
return (block_type == CMARK_NODE_PARAGRAPH ||
|
return (block_type == CMARK_NODE_PARAGRAPH ||
|
||||||
block_type == CMARK_NODE_HEADING ||
|
block_type == CMARK_NODE_HEADING ||
|
||||||
block_type == CMARK_NODE_CODE_BLOCK);
|
block_type == CMARK_NODE_CODE_BLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CMARK_INLINE bool contains_inlines(cmark_node_type block_type) {
|
static CMARK_INLINE bool contains_inlines(cmark_node *node) {
|
||||||
return (block_type == CMARK_NODE_PARAGRAPH ||
|
if (node->extension && node->extension->contains_inlines_func) {
|
||||||
block_type == CMARK_NODE_HEADING ||
|
return node->extension->contains_inlines_func(node->extension, node);
|
||||||
block_type == CMARK_NODE_TABLE_CELL);
|
}
|
||||||
|
|
||||||
|
return (node->type == CMARK_NODE_PARAGRAPH ||
|
||||||
|
node->type == CMARK_NODE_HEADING);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_line(cmark_node *node, cmark_chunk *ch, cmark_parser *parser) {
|
static void add_line(cmark_node *node, cmark_chunk *ch, cmark_parser *parser) {
|
||||||
|
@ -378,7 +366,7 @@ static cmark_node *add_child(cmark_parser *parser, cmark_node *parent,
|
||||||
|
|
||||||
// if 'parent' isn't the kind of node that can accept this child,
|
// if 'parent' isn't the kind of node that can accept this child,
|
||||||
// then back up til we hit a node that can.
|
// then back up til we hit a node that can.
|
||||||
while (!can_contain(S_type(parent), block_type)) {
|
while (!cmark_node_can_contain_type(parent, block_type)) {
|
||||||
parent = finalize(parser, parent);
|
parent = finalize(parser, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +385,7 @@ static cmark_node *add_child(cmark_parser *parser, cmark_node *parent,
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void manage_extensions_special_characters(cmark_parser *parser, bool add) {
|
void cmark_manage_extensions_special_characters(cmark_parser *parser, bool add) {
|
||||||
cmark_llist *tmp_ext;
|
cmark_llist *tmp_ext;
|
||||||
|
|
||||||
for (tmp_ext = parser->inline_syntax_extensions; tmp_ext; tmp_ext=tmp_ext->next) {
|
for (tmp_ext = parser->inline_syntax_extensions; tmp_ext; tmp_ext=tmp_ext->next) {
|
||||||
|
@ -421,18 +409,18 @@ static void process_inlines(cmark_parser *parser,
|
||||||
cmark_node *cur;
|
cmark_node *cur;
|
||||||
cmark_event_type ev_type;
|
cmark_event_type ev_type;
|
||||||
|
|
||||||
manage_extensions_special_characters(parser, true);
|
cmark_manage_extensions_special_characters(parser, true);
|
||||||
|
|
||||||
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||||
cur = cmark_iter_get_node(iter);
|
cur = cmark_iter_get_node(iter);
|
||||||
if (ev_type == CMARK_EVENT_ENTER) {
|
if (ev_type == CMARK_EVENT_ENTER) {
|
||||||
if (contains_inlines(cur->type)) {
|
if (contains_inlines(cur)) {
|
||||||
cmark_parse_inlines(parser, cur, refmap, options);
|
cmark_parse_inlines(parser, cur, refmap, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
manage_extensions_special_characters(parser, false);
|
cmark_manage_extensions_special_characters(parser, false);
|
||||||
|
|
||||||
cmark_iter_free(iter);
|
cmark_iter_free(iter);
|
||||||
}
|
}
|
||||||
|
@ -1289,7 +1277,7 @@ static void S_process_line(cmark_parser *parser, const unsigned char *buffer,
|
||||||
|
|
||||||
/* parser->current might have changed if feed_reentrant was called */
|
/* parser->current might have changed if feed_reentrant was called */
|
||||||
if (current == parser->current)
|
if (current == parser->current)
|
||||||
add_text_to_container(parser, container, last_matched_container, &input);
|
add_text_to_container(parser, container, last_matched_container, &input);
|
||||||
|
|
||||||
finished:
|
finished:
|
||||||
parser->last_line_length = input.len;
|
parser->last_line_length = input.len;
|
||||||
|
@ -1305,6 +1293,7 @@ finished:
|
||||||
|
|
||||||
cmark_node *cmark_parser_finish(cmark_parser *parser) {
|
cmark_node *cmark_parser_finish(cmark_parser *parser) {
|
||||||
cmark_node *res;
|
cmark_node *res;
|
||||||
|
cmark_llist *extensions;
|
||||||
|
|
||||||
/* Parser was already finished once */
|
/* Parser was already finished once */
|
||||||
if (parser->root == NULL)
|
if (parser->root == NULL)
|
||||||
|
@ -1333,6 +1322,15 @@ cmark_node *cmark_parser_finish(cmark_parser *parser) {
|
||||||
|
|
||||||
cmark_parser_reset(parser);
|
cmark_parser_reset(parser);
|
||||||
|
|
||||||
|
for (extensions = parser->syntax_extensions; extensions; extensions = extensions->next) {
|
||||||
|
cmark_syntax_extension *ext = (cmark_syntax_extension *) extensions->data;
|
||||||
|
if (ext->postprocess_func) {
|
||||||
|
cmark_node *processed = ext->postprocess_func(ext, res);
|
||||||
|
if (processed)
|
||||||
|
res = processed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
src/buffer.h
36
src/buffer.h
|
@ -32,22 +32,32 @@ extern unsigned char cmark_strbuf__initbuf[];
|
||||||
* For the cases where CMARK_BUF_INIT cannot be used to do static
|
* For the cases where CMARK_BUF_INIT cannot be used to do static
|
||||||
* initialization.
|
* initialization.
|
||||||
*/
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
|
void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
|
||||||
bufsize_t initial_size);
|
bufsize_t initial_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grow the buffer to hold at least `target_size` bytes.
|
* Grow the buffer to hold at least `target_size` bytes.
|
||||||
*/
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size);
|
void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_free(cmark_strbuf *buf);
|
void cmark_strbuf_free(cmark_strbuf *buf);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b);
|
void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
bufsize_t cmark_strbuf_len(const cmark_strbuf *buf);
|
bufsize_t cmark_strbuf_len(const cmark_strbuf *buf);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b);
|
int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
unsigned char *cmark_strbuf_detach(cmark_strbuf *buf);
|
unsigned char *cmark_strbuf_detach(cmark_strbuf *buf);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize,
|
void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize,
|
||||||
const cmark_strbuf *buf);
|
const cmark_strbuf *buf);
|
||||||
|
|
||||||
|
@ -57,22 +67,48 @@ static CMARK_INLINE const char *cmark_strbuf_cstr(const cmark_strbuf *buf) {
|
||||||
|
|
||||||
#define cmark_strbuf_at(buf, n) ((buf)->ptr[n])
|
#define cmark_strbuf_at(buf, n) ((buf)->ptr[n])
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
|
void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
|
||||||
bufsize_t len);
|
bufsize_t len);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_sets(cmark_strbuf *buf, const char *string);
|
void cmark_strbuf_sets(cmark_strbuf *buf, const char *string);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_putc(cmark_strbuf *buf, int c);
|
void cmark_strbuf_putc(cmark_strbuf *buf, int c);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
|
void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
|
||||||
bufsize_t len);
|
bufsize_t len);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_puts(cmark_strbuf *buf, const char *string);
|
void cmark_strbuf_puts(cmark_strbuf *buf, const char *string);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_clear(cmark_strbuf *buf);
|
void cmark_strbuf_clear(cmark_strbuf *buf);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos);
|
bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos);
|
bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n);
|
void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len);
|
void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_rtrim(cmark_strbuf *buf);
|
void cmark_strbuf_rtrim(cmark_strbuf *buf);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_trim(cmark_strbuf *buf);
|
void cmark_strbuf_trim(cmark_strbuf *buf);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_normalize_whitespace(cmark_strbuf *s);
|
void cmark_strbuf_normalize_whitespace(cmark_strbuf *s);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_strbuf_unescape(cmark_strbuf *s);
|
void cmark_strbuf_unescape(cmark_strbuf *s);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
15
src/cmark.c
15
src/cmark.c
|
@ -7,6 +7,9 @@
|
||||||
#include "cmark.h"
|
#include "cmark.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
|
cmark_node_type CMARK_NODE_LAST_BLOCK = CMARK_NODE_THEMATIC_BREAK;
|
||||||
|
cmark_node_type CMARK_NODE_LAST_INLINE = CMARK_NODE_IMAGE;
|
||||||
|
|
||||||
int cmark_version() { return CMARK_VERSION; }
|
int cmark_version() { return CMARK_VERSION; }
|
||||||
|
|
||||||
const char *cmark_version_string() { return CMARK_VERSION_STRING; }
|
const char *cmark_version_string() { return CMARK_VERSION_STRING; }
|
||||||
|
@ -41,18 +44,8 @@ char *cmark_markdown_to_html(const char *text, size_t len, int options) {
|
||||||
|
|
||||||
doc = cmark_parse_document(text, len, options);
|
doc = cmark_parse_document(text, len, options);
|
||||||
|
|
||||||
result = cmark_render_html(doc, options);
|
result = cmark_render_html(doc, options, NULL);
|
||||||
cmark_node_free(doc);
|
cmark_node_free(doc);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmark_init(void) {
|
|
||||||
cmark_discover_plugins();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cmark_deinit(void) {
|
|
||||||
cmark_release_plugins();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
102
src/cmark.h
102
src/cmark.h
|
@ -1,9 +1,9 @@
|
||||||
#ifndef CMARK_H
|
#ifndef CMARK_CMARK_H
|
||||||
#define CMARK_H
|
#define CMARK_CMARK_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <cmark_export.h>
|
#include "cmark_export.h"
|
||||||
#include <cmark_version.h>
|
#include "cmark_version.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -30,49 +30,44 @@ char *cmark_markdown_to_html(const char *text, size_t len, int options);
|
||||||
/** ## Node Structure
|
/** ## Node Structure
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define CMARK_NODE_TYPE_PRESENT (0x8000)
|
||||||
|
#define CMARK_NODE_TYPE_BLOCK (CMARK_NODE_TYPE_PRESENT | 0x0000)
|
||||||
|
#define CMARK_NODE_TYPE_INLINE (CMARK_NODE_TYPE_PRESENT | 0x4000)
|
||||||
|
#define CMARK_NODE_TYPE_MASK (0xc000)
|
||||||
|
#define CMARK_NODE_VALUE_MASK (0x3fff)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* Error status */
|
/* Error status */
|
||||||
CMARK_NODE_NONE,
|
CMARK_NODE_NONE = 0x0000,
|
||||||
|
|
||||||
/* Block */
|
/* Block */
|
||||||
CMARK_NODE_DOCUMENT,
|
CMARK_NODE_DOCUMENT = CMARK_NODE_TYPE_BLOCK | 0x0001,
|
||||||
CMARK_NODE_BLOCK_QUOTE,
|
CMARK_NODE_BLOCK_QUOTE = CMARK_NODE_TYPE_BLOCK | 0x0002,
|
||||||
CMARK_NODE_LIST,
|
CMARK_NODE_LIST = CMARK_NODE_TYPE_BLOCK | 0x0003,
|
||||||
CMARK_NODE_ITEM,
|
CMARK_NODE_ITEM = CMARK_NODE_TYPE_BLOCK | 0x0004,
|
||||||
CMARK_NODE_CODE_BLOCK,
|
CMARK_NODE_CODE_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0005,
|
||||||
CMARK_NODE_HTML_BLOCK,
|
CMARK_NODE_HTML_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0006,
|
||||||
CMARK_NODE_CUSTOM_BLOCK,
|
CMARK_NODE_CUSTOM_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0007,
|
||||||
CMARK_NODE_PARAGRAPH,
|
CMARK_NODE_PARAGRAPH = CMARK_NODE_TYPE_BLOCK | 0x0008,
|
||||||
CMARK_NODE_HEADING,
|
CMARK_NODE_HEADING = CMARK_NODE_TYPE_BLOCK | 0x0009,
|
||||||
CMARK_NODE_THEMATIC_BREAK,
|
CMARK_NODE_THEMATIC_BREAK = CMARK_NODE_TYPE_BLOCK | 0x000a,
|
||||||
|
|
||||||
/* blocks with no syntax rules in the current specification */
|
|
||||||
CMARK_NODE_TABLE,
|
|
||||||
CMARK_NODE_TABLE_ROW,
|
|
||||||
CMARK_NODE_TABLE_CELL,
|
|
||||||
|
|
||||||
CMARK_NODE_FIRST_BLOCK = CMARK_NODE_DOCUMENT,
|
|
||||||
CMARK_NODE_LAST_BLOCK = CMARK_NODE_TABLE_CELL,
|
|
||||||
|
|
||||||
/* Inline */
|
/* Inline */
|
||||||
CMARK_NODE_TEXT,
|
CMARK_NODE_TEXT = CMARK_NODE_TYPE_INLINE | 0x0001,
|
||||||
CMARK_NODE_SOFTBREAK,
|
CMARK_NODE_SOFTBREAK = CMARK_NODE_TYPE_INLINE | 0x0002,
|
||||||
CMARK_NODE_LINEBREAK,
|
CMARK_NODE_LINEBREAK = CMARK_NODE_TYPE_INLINE | 0x0003,
|
||||||
CMARK_NODE_CODE,
|
CMARK_NODE_CODE = CMARK_NODE_TYPE_INLINE | 0x0004,
|
||||||
CMARK_NODE_HTML_INLINE,
|
CMARK_NODE_HTML_INLINE = CMARK_NODE_TYPE_INLINE | 0x0005,
|
||||||
CMARK_NODE_CUSTOM_INLINE,
|
CMARK_NODE_CUSTOM_INLINE = CMARK_NODE_TYPE_INLINE | 0x0006,
|
||||||
CMARK_NODE_EMPH,
|
CMARK_NODE_EMPH = CMARK_NODE_TYPE_INLINE | 0x0007,
|
||||||
CMARK_NODE_STRONG,
|
CMARK_NODE_STRONG = CMARK_NODE_TYPE_INLINE | 0x0008,
|
||||||
CMARK_NODE_LINK,
|
CMARK_NODE_LINK = CMARK_NODE_TYPE_INLINE | 0x0009,
|
||||||
CMARK_NODE_IMAGE,
|
CMARK_NODE_IMAGE = CMARK_NODE_TYPE_INLINE | 0x000a,
|
||||||
|
|
||||||
/* inlines with no syntax rules in the current specification */
|
|
||||||
CMARK_NODE_STRIKETHROUGH,
|
|
||||||
|
|
||||||
CMARK_NODE_FIRST_INLINE = CMARK_NODE_TEXT,
|
|
||||||
CMARK_NODE_LAST_INLINE = CMARK_NODE_STRIKETHROUGH,
|
|
||||||
} cmark_node_type;
|
} cmark_node_type;
|
||||||
|
|
||||||
|
extern cmark_node_type CMARK_NODE_LAST_BLOCK;
|
||||||
|
extern cmark_node_type CMARK_NODE_LAST_INLINE;
|
||||||
|
|
||||||
/* For backwards compatibility: */
|
/* For backwards compatibility: */
|
||||||
#define CMARK_NODE_HEADER CMARK_NODE_HEADING
|
#define CMARK_NODE_HEADER CMARK_NODE_HEADING
|
||||||
#define CMARK_NODE_HRULE CMARK_NODE_THEMATIC_BREAK
|
#define CMARK_NODE_HRULE CMARK_NODE_THEMATIC_BREAK
|
||||||
|
@ -95,8 +90,6 @@ typedef struct cmark_node cmark_node;
|
||||||
typedef struct cmark_parser cmark_parser;
|
typedef struct cmark_parser cmark_parser;
|
||||||
typedef struct cmark_iter cmark_iter;
|
typedef struct cmark_iter cmark_iter;
|
||||||
|
|
||||||
typedef void (*cmark_free_func) (void *user_data);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## Custom memory allocator support
|
* ## Custom memory allocator support
|
||||||
*/
|
*/
|
||||||
|
@ -128,6 +121,10 @@ cmark_mem *cmark_get_arena_mem_allocator();
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
void cmark_arena_reset(void);
|
void cmark_arena_reset(void);
|
||||||
|
|
||||||
|
/** Callback for freeing user data with a 'cmark_mem' context.
|
||||||
|
*/
|
||||||
|
typedef void (*cmark_free_func) (cmark_mem *mem, void *user_data);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ## Basic data structures
|
* ## Basic data structures
|
||||||
|
@ -152,21 +149,23 @@ typedef struct _cmark_llist
|
||||||
* head of the list.
|
* head of the list.
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
cmark_llist * cmark_llist_append (cmark_llist * head,
|
cmark_llist * cmark_llist_append (cmark_mem * mem,
|
||||||
|
cmark_llist * head,
|
||||||
void * data);
|
void * data);
|
||||||
|
|
||||||
/** Free the list starting with 'head', calling 'free_func' with the
|
/** Free the list starting with 'head', calling 'free_func' with the
|
||||||
* data pointer of each of its elements
|
* data pointer of each of its elements
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
void cmark_llist_free_full (cmark_llist * head,
|
void cmark_llist_free_full (cmark_mem * mem,
|
||||||
|
cmark_llist * head,
|
||||||
cmark_free_func free_func);
|
cmark_free_func free_func);
|
||||||
|
|
||||||
/** Free the list starting with 'head'
|
/** Free the list starting with 'head'
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
void cmark_llist_free (cmark_llist * head);
|
void cmark_llist_free (cmark_mem * mem,
|
||||||
|
cmark_llist * head);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## Creating and Destroying Nodes
|
* ## Creating and Destroying Nodes
|
||||||
|
@ -479,11 +478,6 @@ CMARK_EXPORT int cmark_node_get_end_line(cmark_node *node);
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT int cmark_node_get_end_column(cmark_node *node);
|
CMARK_EXPORT int cmark_node_get_end_column(cmark_node *node);
|
||||||
|
|
||||||
CMARK_EXPORT int cmark_node_get_n_table_columns(cmark_node *node);
|
|
||||||
CMARK_EXPORT int cmark_node_set_n_table_columns(cmark_node *node, int n_columns);
|
|
||||||
CMARK_EXPORT int cmark_node_is_table_header(cmark_node *node);
|
|
||||||
CMARK_EXPORT int cmark_node_set_is_table_header(cmark_node *node, int is_table_header);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## Tree Manipulation
|
* ## Tree Manipulation
|
||||||
*/
|
*/
|
||||||
|
@ -522,6 +516,10 @@ CMARK_EXPORT int cmark_node_append_child(cmark_node *node, cmark_node *child);
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT void cmark_consolidate_text_nodes(cmark_node *root);
|
CMARK_EXPORT void cmark_consolidate_text_nodes(cmark_node *root);
|
||||||
|
|
||||||
|
/** Ensures a node and all its children own their own chunk memory.
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT void cmark_node_own(cmark_node *root);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## Parsing
|
* ## Parsing
|
||||||
*
|
*
|
||||||
|
@ -605,13 +603,13 @@ char *cmark_render_xml_with_mem(cmark_node *root, int options, cmark_mem *mem);
|
||||||
* responsibility to free the returned buffer.
|
* responsibility to free the returned buffer.
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
char *cmark_render_html(cmark_node *root, int options);
|
char *cmark_render_html(cmark_node *root, int options, cmark_llist *extensions);
|
||||||
|
|
||||||
/** As for 'cmark_render_html', but specifying the allocator to use for
|
/** As for 'cmark_render_html', but specifying the allocator to use for
|
||||||
* the resulting string.
|
* the resulting string.
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
char *cmark_render_html_with_mem(cmark_node *root, int options, cmark_mem *mem);
|
char *cmark_render_html_with_mem(cmark_node *root, int options, cmark_llist *extensions, cmark_mem *mem);
|
||||||
|
|
||||||
/** Render a 'node' tree as a groff man page, without the header.
|
/** Render a 'node' tree as a groff man page, without the header.
|
||||||
* It is the caller's responsibility to free the returned buffer.
|
* It is the caller's responsibility to free the returned buffer.
|
||||||
|
|
|
@ -5,18 +5,25 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "cmark_export.h"
|
||||||
|
|
||||||
/** Locale-independent versions of functions from ctype.h.
|
/** Locale-independent versions of functions from ctype.h.
|
||||||
* We want cmark to behave the same no matter what the system locale.
|
* We want cmark to behave the same no matter what the system locale.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
int cmark_isspace(char c);
|
int cmark_isspace(char c);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
int cmark_ispunct(char c);
|
int cmark_ispunct(char c);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
int cmark_isalnum(char c);
|
int cmark_isalnum(char c);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
int cmark_isdigit(char c);
|
int cmark_isdigit(char c);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
int cmark_isalpha(char c);
|
int cmark_isalpha(char c);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
#ifndef CMARK_EXTENSION_API_H
|
#ifndef CMARK_CMARK_EXTENSION_API_H
|
||||||
#define CMARK_EXTENSION_API_H
|
#define CMARK_CMARK_EXTENSION_API_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cmark.h>
|
#include <cmark.h>
|
||||||
#include "buffer.h"
|
#include <render.h>
|
||||||
|
#include <buffer.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## Extension Support
|
* ## Extension Support
|
||||||
|
@ -217,16 +218,48 @@ typedef int (*cmark_match_block_func) (cmark_syntax_extension *extension,
|
||||||
int len,
|
int len,
|
||||||
cmark_node *container);
|
cmark_node *container);
|
||||||
|
|
||||||
|
typedef const char *(*cmark_get_type_string_func) (cmark_syntax_extension *extension,
|
||||||
|
cmark_node *node);
|
||||||
|
|
||||||
|
typedef int (*cmark_can_contain_func) (cmark_syntax_extension *extension,
|
||||||
|
cmark_node *node,
|
||||||
|
cmark_node_type child);
|
||||||
|
|
||||||
|
typedef int (*cmark_contains_inlines_func) (cmark_syntax_extension *extension,
|
||||||
|
cmark_node *node);
|
||||||
|
|
||||||
|
typedef void (*cmark_common_render_func) (cmark_syntax_extension *extension,
|
||||||
|
cmark_renderer *renderer,
|
||||||
|
cmark_node *node,
|
||||||
|
cmark_event_type ev_type,
|
||||||
|
int options);
|
||||||
|
|
||||||
|
typedef void (*cmark_html_render_func) (cmark_syntax_extension *extension,
|
||||||
|
cmark_html_renderer *renderer,
|
||||||
|
cmark_node *node,
|
||||||
|
cmark_event_type ev_type,
|
||||||
|
int options);
|
||||||
|
|
||||||
|
typedef int (*cmark_html_filter_func) (cmark_syntax_extension *extension,
|
||||||
|
const unsigned char *tag,
|
||||||
|
size_t tag_len);
|
||||||
|
|
||||||
|
typedef cmark_node *(*cmark_postprocess_func) (cmark_syntax_extension *extension,
|
||||||
|
cmark_node *root);
|
||||||
|
|
||||||
/** Free a cmark_syntax_extension.
|
/** Free a cmark_syntax_extension.
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
void cmark_syntax_extension_free (cmark_syntax_extension *extension);
|
void cmark_syntax_extension_free (cmark_mem *mem, cmark_syntax_extension *extension);
|
||||||
|
|
||||||
/** Return a newly-constructed cmark_syntax_extension, named 'name'.
|
/** Return a newly-constructed cmark_syntax_extension, named 'name'.
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
cmark_syntax_extension *cmark_syntax_extension_new (const char *name);
|
cmark_syntax_extension *cmark_syntax_extension_new (const char *name);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
|
cmark_node_type cmark_syntax_extension_add_node(int is_inline);
|
||||||
|
|
||||||
/** See the documentation for 'cmark_syntax_extension'
|
/** See the documentation for 'cmark_syntax_extension'
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
|
@ -257,6 +290,54 @@ CMARK_EXPORT
|
||||||
void cmark_syntax_extension_set_special_inline_chars(cmark_syntax_extension *extension,
|
void cmark_syntax_extension_set_special_inline_chars(cmark_syntax_extension *extension,
|
||||||
cmark_llist *special_chars);
|
cmark_llist *special_chars);
|
||||||
|
|
||||||
|
/** See the documentation for 'cmark_syntax_extension'
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_syntax_extension_set_get_type_string_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_get_type_string_func func);
|
||||||
|
|
||||||
|
/** See the documentation for 'cmark_syntax_extension'
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_syntax_extension_set_can_contain_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_can_contain_func func);
|
||||||
|
|
||||||
|
/** See the documentation for 'cmark_syntax_extension'
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_syntax_extension_set_contains_inlines_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_contains_inlines_func func);
|
||||||
|
|
||||||
|
/** See the documentation for 'cmark_syntax_extension'
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_syntax_extension_set_commonmark_render_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_common_render_func func);
|
||||||
|
|
||||||
|
/** See the documentation for 'cmark_syntax_extension'
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_syntax_extension_set_latex_render_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_common_render_func func);
|
||||||
|
|
||||||
|
/** See the documentation for 'cmark_syntax_extension'
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_syntax_extension_set_man_render_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_common_render_func func);
|
||||||
|
|
||||||
|
/** See the documentation for 'cmark_syntax_extension'
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_syntax_extension_set_html_render_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_html_render_func func);
|
||||||
|
|
||||||
|
/** See the documentation for 'cmark_syntax_extension'
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_syntax_extension_set_html_filter_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_html_filter_func func);
|
||||||
|
|
||||||
/** See the documentation for 'cmark_syntax_extension'
|
/** See the documentation for 'cmark_syntax_extension'
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
|
@ -264,6 +345,12 @@ void cmark_syntax_extension_set_private(cmark_syntax_extension *extension,
|
||||||
void *priv,
|
void *priv,
|
||||||
cmark_free_func free_func);
|
cmark_free_func free_func);
|
||||||
|
|
||||||
|
/** See the documentation for 'cmark_syntax_extension'
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_syntax_extension_set_postprocess_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_postprocess_func func);
|
||||||
|
|
||||||
/** Return the index of the line currently being parsed, starting with 1.
|
/** Return the index of the line currently being parsed, starting with 1.
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
|
@ -477,6 +564,30 @@ void cmark_inline_parser_advance_offset(cmark_inline_parser *parser);
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
int cmark_inline_parser_get_offset(cmark_inline_parser *parser);
|
int cmark_inline_parser_get_offset(cmark_inline_parser *parser);
|
||||||
|
|
||||||
|
/** Set the offset in bytes in the chunk being processed by the given inline parser.
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_inline_parser_set_offset(cmark_inline_parser *parser, int offset);
|
||||||
|
|
||||||
|
/** Gets the cmark_chunk being operated on by the given inline parser.
|
||||||
|
* Use cmark_inline_parser_get_offset to get our current position in the chunk.
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
cmark_chunk *cmark_inline_parser_get_chunk(cmark_inline_parser *parser);
|
||||||
|
|
||||||
|
/** Returns 1 if the inline parser is currently in a bracket; pass 1 for 'image'
|
||||||
|
* if you want to know about an image-type bracket, 0 for link-type. */
|
||||||
|
CMARK_EXPORT
|
||||||
|
int cmark_inline_parser_in_bracket(cmark_inline_parser *parser, int image);
|
||||||
|
|
||||||
|
/** Remove the last n characters from the last child of the given node.
|
||||||
|
* This only works where all n characters are in the single last child, and the last
|
||||||
|
* child is CMARK_NODE_TEXT.
|
||||||
|
*/
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_node_unput(cmark_node *node, int n);
|
||||||
|
|
||||||
|
|
||||||
/** Get the character located at the current inline parsing offset
|
/** Get the character located at the current inline parsing offset
|
||||||
*/
|
*/
|
||||||
CMARK_EXPORT
|
CMARK_EXPORT
|
||||||
|
@ -539,6 +650,10 @@ int cmark_inline_parser_scan_delimiters(cmark_inline_parser *parser,
|
||||||
int *right_flanking,
|
int *right_flanking,
|
||||||
int *punct_before,
|
int *punct_before,
|
||||||
int *punct_after);
|
int *punct_after);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
|
void cmark_manage_extensions_special_characters(cmark_parser *parser, bool add);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
#include "scanners.h"
|
#include "scanners.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
#include "syntax_extension.h"
|
||||||
|
|
||||||
#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
|
#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
|
||||||
#define LIT(s) renderer->out(renderer, s, false, LITERAL)
|
#define LIT(s) renderer->out(renderer, s, false, LITERAL)
|
||||||
|
@ -151,8 +152,7 @@ static bool is_autolink(cmark_node *node) {
|
||||||
// if there is no block-level ancestor, returns NULL.
|
// if there is no block-level ancestor, returns NULL.
|
||||||
static cmark_node *get_containing_block(cmark_node *node) {
|
static cmark_node *get_containing_block(cmark_node *node) {
|
||||||
while (node) {
|
while (node) {
|
||||||
if (node->type >= CMARK_NODE_FIRST_BLOCK &&
|
if (CMARK_NODE_BLOCK_P(node)) {
|
||||||
node->type <= CMARK_NODE_LAST_BLOCK) {
|
|
||||||
return node;
|
return node;
|
||||||
} else {
|
} else {
|
||||||
node = node->parent;
|
node = node->parent;
|
||||||
|
@ -191,6 +191,11 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||||
cmark_node_get_list_tight(tmp->parent->parent)));
|
cmark_node_get_list_tight(tmp->parent->parent)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->extension && node->extension->commonmark_render_func) {
|
||||||
|
node->extension->commonmark_render_func(node->extension, renderer, node, ev_type, options);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case CMARK_NODE_DOCUMENT:
|
case CMARK_NODE_DOCUMENT:
|
||||||
break;
|
break;
|
||||||
|
@ -335,33 +340,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_TABLE:
|
|
||||||
BLANKLINE();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMARK_NODE_TABLE_ROW:
|
|
||||||
if (entering) {
|
|
||||||
CR();
|
|
||||||
LIT("|");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CMARK_NODE_TABLE_CELL:
|
|
||||||
if (entering) {
|
|
||||||
} else {
|
|
||||||
LIT(" |");
|
|
||||||
if (node->parent->as.table_row.is_header && !node->next) {
|
|
||||||
int i;
|
|
||||||
int n_cols = node->parent->parent->as.table.n_columns;
|
|
||||||
CR();
|
|
||||||
LIT("|");
|
|
||||||
for (i = 0; i < n_cols; i++) {
|
|
||||||
LIT(" --- |");
|
|
||||||
}
|
|
||||||
CR();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMARK_NODE_TEXT:
|
case CMARK_NODE_TEXT:
|
||||||
OUT(cmark_node_get_literal(node), allow_wrap, NORMAL);
|
OUT(cmark_node_get_literal(node), allow_wrap, NORMAL);
|
||||||
break;
|
break;
|
||||||
|
@ -484,10 +462,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_STRIKETHROUGH:
|
|
||||||
OUT(cmark_node_get_string_content(node), false, LITERAL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -69,8 +69,6 @@ CMARK_INLINE int c99_snprintf(char *outBuf, size_t size, const char *format, ...
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EXTENSION_DIR LIBDIR "/extensions"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,17 +31,23 @@ extern "C" {
|
||||||
#define HOUDINI_ESCAPED_SIZE(x) (((x)*12) / 10)
|
#define HOUDINI_ESCAPED_SIZE(x) (((x)*12) / 10)
|
||||||
#define HOUDINI_UNESCAPED_SIZE(x) (x)
|
#define HOUDINI_UNESCAPED_SIZE(x) (x)
|
||||||
|
|
||||||
extern bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src,
|
CMARK_EXPORT
|
||||||
|
bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src,
|
||||||
bufsize_t size);
|
bufsize_t size);
|
||||||
extern int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src,
|
CMARK_EXPORT
|
||||||
|
int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src,
|
||||||
bufsize_t size);
|
bufsize_t size);
|
||||||
extern int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src,
|
CMARK_EXPORT
|
||||||
|
int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src,
|
||||||
bufsize_t size, int secure);
|
bufsize_t size, int secure);
|
||||||
extern int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src,
|
CMARK_EXPORT
|
||||||
|
int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src,
|
||||||
bufsize_t size);
|
bufsize_t size);
|
||||||
extern void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src,
|
CMARK_EXPORT
|
||||||
|
void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src,
|
||||||
bufsize_t size);
|
bufsize_t size);
|
||||||
extern int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src,
|
CMARK_EXPORT
|
||||||
|
int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src,
|
||||||
bufsize_t size);
|
bufsize_t size);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -48,7 +48,7 @@ int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src, bufsize_t size,
|
||||||
if (unlikely(i >= size))
|
if (unlikely(i >= size))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* The forward slash is only escaped in secure mode */
|
/* The forward slash and single quote are only escaped in secure mode */
|
||||||
if ((src[i] == '/' || src[i] == '\'') && !secure) {
|
if ((src[i] == '/' || src[i] == '\'') && !secure) {
|
||||||
cmark_strbuf_putc(ob, src[i]);
|
cmark_strbuf_putc(ob, src[i]);
|
||||||
} else {
|
} else {
|
||||||
|
|
230
src/html.c
230
src/html.c
|
@ -5,12 +5,10 @@
|
||||||
#include "cmark_ctype.h"
|
#include "cmark_ctype.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "cmark.h"
|
#include "cmark.h"
|
||||||
#include "node.h"
|
|
||||||
#include "buffer.h"
|
|
||||||
#include "houdini.h"
|
#include "houdini.h"
|
||||||
#include "scanners.h"
|
#include "scanners.h"
|
||||||
|
#include "syntax_extension.h"
|
||||||
#define BUFFER_SIZE 100
|
#include "html.h"
|
||||||
|
|
||||||
// Functions to convert cmark_nodes to HTML strings.
|
// Functions to convert cmark_nodes to HTML strings.
|
||||||
|
|
||||||
|
@ -19,46 +17,67 @@ static void escape_html(cmark_strbuf *dest, const unsigned char *source,
|
||||||
houdini_escape_html0(dest, source, length, 0);
|
houdini_escape_html0(dest, source, length, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CMARK_INLINE void cr(cmark_strbuf *html) {
|
static void filter_html_block(cmark_html_renderer *renderer, uint8_t *data, size_t len) {
|
||||||
if (html->size && html->ptr[html->size - 1] != '\n')
|
cmark_strbuf *html = renderer->html;
|
||||||
cmark_strbuf_putc(html, '\n');
|
cmark_llist *it;
|
||||||
}
|
cmark_syntax_extension *ext;
|
||||||
|
bool filtered;
|
||||||
|
uint8_t *match;
|
||||||
|
|
||||||
struct render_state {
|
while (len) {
|
||||||
cmark_strbuf *html;
|
match = (uint8_t *) memchr(data, '<', len);
|
||||||
cmark_node *plain;
|
if (!match)
|
||||||
bool need_closing_table_body;
|
break;
|
||||||
bool in_table_header;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void S_render_sourcepos(cmark_node *node, cmark_strbuf *html,
|
if (match != data) {
|
||||||
int options) {
|
cmark_strbuf_put(html, data, match - data);
|
||||||
char buffer[BUFFER_SIZE];
|
len -= (match - data);
|
||||||
if (CMARK_OPT_SOURCEPOS & options) {
|
data = match;
|
||||||
snprintf(buffer, BUFFER_SIZE, " data-sourcepos=\"%d:%d-%d:%d\"",
|
}
|
||||||
cmark_node_get_start_line(node), cmark_node_get_start_column(node),
|
|
||||||
cmark_node_get_end_line(node), cmark_node_get_end_column(node));
|
filtered = false;
|
||||||
cmark_strbuf_puts(html, buffer);
|
for (it = renderer->filter_extensions; it; it = it->next) {
|
||||||
|
ext = ((cmark_syntax_extension *) it->data);
|
||||||
|
if (!ext->html_filter_func(ext, data, len)) {
|
||||||
|
filtered = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filtered) {
|
||||||
|
cmark_strbuf_putc(html, '<');
|
||||||
|
} else {
|
||||||
|
cmark_strbuf_puts(html, "<");
|
||||||
|
}
|
||||||
|
|
||||||
|
++data;
|
||||||
|
--len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
cmark_strbuf_put(html, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
|
||||||
struct render_state *state, int options) {
|
cmark_event_type ev_type, int options) {
|
||||||
cmark_node *parent;
|
cmark_node *parent;
|
||||||
cmark_node *grandparent;
|
cmark_node *grandparent;
|
||||||
cmark_strbuf *html = state->html;
|
cmark_strbuf *html = renderer->html;
|
||||||
|
cmark_llist *it;
|
||||||
|
cmark_syntax_extension *ext;
|
||||||
char start_heading[] = "<h0";
|
char start_heading[] = "<h0";
|
||||||
char end_heading[] = "</h0";
|
char end_heading[] = "</h0";
|
||||||
bool tight;
|
bool tight;
|
||||||
|
bool filtered;
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||||
|
|
||||||
if (state->plain == node) { // back at original node
|
if (renderer->plain == node) { // back at original node
|
||||||
state->plain = NULL;
|
renderer->plain = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->plain != NULL) {
|
if (renderer->plain != NULL) {
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case CMARK_NODE_TEXT:
|
case CMARK_NODE_TEXT:
|
||||||
case CMARK_NODE_CODE:
|
case CMARK_NODE_CODE:
|
||||||
|
@ -77,18 +96,23 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->extension && node->extension->html_render_func) {
|
||||||
|
node->extension->html_render_func(node->extension, renderer, node, ev_type, options);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case CMARK_NODE_DOCUMENT:
|
case CMARK_NODE_DOCUMENT:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_BLOCK_QUOTE:
|
case CMARK_NODE_BLOCK_QUOTE:
|
||||||
if (entering) {
|
if (entering) {
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
cmark_strbuf_puts(html, "<blockquote");
|
cmark_strbuf_puts(html, "<blockquote");
|
||||||
S_render_sourcepos(node, html, options);
|
cmark_html_render_sourcepos(node, html, options);
|
||||||
cmark_strbuf_puts(html, ">\n");
|
cmark_strbuf_puts(html, ">\n");
|
||||||
} else {
|
} else {
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
cmark_strbuf_puts(html, "</blockquote>\n");
|
cmark_strbuf_puts(html, "</blockquote>\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -98,19 +122,19 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
int start = node->as.list.start;
|
int start = node->as.list.start;
|
||||||
|
|
||||||
if (entering) {
|
if (entering) {
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
if (list_type == CMARK_BULLET_LIST) {
|
if (list_type == CMARK_BULLET_LIST) {
|
||||||
cmark_strbuf_puts(html, "<ul");
|
cmark_strbuf_puts(html, "<ul");
|
||||||
S_render_sourcepos(node, html, options);
|
cmark_html_render_sourcepos(node, html, options);
|
||||||
cmark_strbuf_puts(html, ">\n");
|
cmark_strbuf_puts(html, ">\n");
|
||||||
} else if (start == 1) {
|
} else if (start == 1) {
|
||||||
cmark_strbuf_puts(html, "<ol");
|
cmark_strbuf_puts(html, "<ol");
|
||||||
S_render_sourcepos(node, html, options);
|
cmark_html_render_sourcepos(node, html, options);
|
||||||
cmark_strbuf_puts(html, ">\n");
|
cmark_strbuf_puts(html, ">\n");
|
||||||
} else {
|
} else {
|
||||||
snprintf(buffer, BUFFER_SIZE, "<ol start=\"%d\"", start);
|
snprintf(buffer, BUFFER_SIZE, "<ol start=\"%d\"", start);
|
||||||
cmark_strbuf_puts(html, buffer);
|
cmark_strbuf_puts(html, buffer);
|
||||||
S_render_sourcepos(node, html, options);
|
cmark_html_render_sourcepos(node, html, options);
|
||||||
cmark_strbuf_puts(html, ">\n");
|
cmark_strbuf_puts(html, ">\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,9 +146,9 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
|
|
||||||
case CMARK_NODE_ITEM:
|
case CMARK_NODE_ITEM:
|
||||||
if (entering) {
|
if (entering) {
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
cmark_strbuf_puts(html, "<li");
|
cmark_strbuf_puts(html, "<li");
|
||||||
S_render_sourcepos(node, html, options);
|
cmark_html_render_sourcepos(node, html, options);
|
||||||
cmark_strbuf_putc(html, '>');
|
cmark_strbuf_putc(html, '>');
|
||||||
} else {
|
} else {
|
||||||
cmark_strbuf_puts(html, "</li>\n");
|
cmark_strbuf_puts(html, "</li>\n");
|
||||||
|
@ -133,10 +157,10 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
|
|
||||||
case CMARK_NODE_HEADING:
|
case CMARK_NODE_HEADING:
|
||||||
if (entering) {
|
if (entering) {
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
start_heading[2] = (char)('0' + node->as.heading.level);
|
start_heading[2] = (char)('0' + node->as.heading.level);
|
||||||
cmark_strbuf_puts(html, start_heading);
|
cmark_strbuf_puts(html, start_heading);
|
||||||
S_render_sourcepos(node, html, options);
|
cmark_html_render_sourcepos(node, html, options);
|
||||||
cmark_strbuf_putc(html, '>');
|
cmark_strbuf_putc(html, '>');
|
||||||
} else {
|
} else {
|
||||||
end_heading[3] = (char)('0' + node->as.heading.level);
|
end_heading[3] = (char)('0' + node->as.heading.level);
|
||||||
|
@ -146,11 +170,11 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_CODE_BLOCK:
|
case CMARK_NODE_CODE_BLOCK:
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
|
|
||||||
if (node->as.code.info.len == 0) {
|
if (node->as.code.info.len == 0) {
|
||||||
cmark_strbuf_puts(html, "<pre");
|
cmark_strbuf_puts(html, "<pre");
|
||||||
S_render_sourcepos(node, html, options);
|
cmark_html_render_sourcepos(node, html, options);
|
||||||
cmark_strbuf_puts(html, "><code>");
|
cmark_strbuf_puts(html, "><code>");
|
||||||
} else {
|
} else {
|
||||||
bufsize_t first_tag = 0;
|
bufsize_t first_tag = 0;
|
||||||
|
@ -160,7 +184,7 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmark_strbuf_puts(html, "<pre");
|
cmark_strbuf_puts(html, "<pre");
|
||||||
S_render_sourcepos(node, html, options);
|
cmark_html_render_sourcepos(node, html, options);
|
||||||
cmark_strbuf_puts(html, "><code class=\"language-");
|
cmark_strbuf_puts(html, "><code class=\"language-");
|
||||||
escape_html(html, node->as.code.info.data, first_tag);
|
escape_html(html, node->as.code.info.data, first_tag);
|
||||||
cmark_strbuf_puts(html, "\">");
|
cmark_strbuf_puts(html, "\">");
|
||||||
|
@ -171,17 +195,19 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_HTML_BLOCK:
|
case CMARK_NODE_HTML_BLOCK:
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
if (options & CMARK_OPT_SAFE) {
|
if (options & CMARK_OPT_SAFE) {
|
||||||
cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
|
cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
|
||||||
|
} else if (renderer->filter_extensions) {
|
||||||
|
filter_html_block(renderer, node->as.literal.data, node->as.literal.len);
|
||||||
} else {
|
} else {
|
||||||
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
|
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
|
||||||
}
|
}
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_CUSTOM_BLOCK:
|
case CMARK_NODE_CUSTOM_BLOCK:
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
if (entering) {
|
if (entering) {
|
||||||
cmark_strbuf_put(html, node->as.custom.on_enter.data,
|
cmark_strbuf_put(html, node->as.custom.on_enter.data,
|
||||||
node->as.custom.on_enter.len);
|
node->as.custom.on_enter.len);
|
||||||
|
@ -189,13 +215,13 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
cmark_strbuf_put(html, node->as.custom.on_exit.data,
|
cmark_strbuf_put(html, node->as.custom.on_exit.data,
|
||||||
node->as.custom.on_exit.len);
|
node->as.custom.on_exit.len);
|
||||||
}
|
}
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_THEMATIC_BREAK:
|
case CMARK_NODE_THEMATIC_BREAK:
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
cmark_strbuf_puts(html, "<hr");
|
cmark_strbuf_puts(html, "<hr");
|
||||||
S_render_sourcepos(node, html, options);
|
cmark_html_render_sourcepos(node, html, options);
|
||||||
cmark_strbuf_puts(html, " />\n");
|
cmark_strbuf_puts(html, " />\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -209,9 +235,9 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
}
|
}
|
||||||
if (!tight) {
|
if (!tight) {
|
||||||
if (entering) {
|
if (entering) {
|
||||||
cr(html);
|
cmark_html_render_cr(html);
|
||||||
cmark_strbuf_puts(html, "<p");
|
cmark_strbuf_puts(html, "<p");
|
||||||
S_render_sourcepos(node, html, options);
|
cmark_html_render_sourcepos(node, html, options);
|
||||||
cmark_strbuf_putc(html, '>');
|
cmark_strbuf_putc(html, '>');
|
||||||
} else {
|
} else {
|
||||||
cmark_strbuf_puts(html, "</p>\n");
|
cmark_strbuf_puts(html, "</p>\n");
|
||||||
|
@ -219,65 +245,6 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_TABLE:
|
|
||||||
if (entering) {
|
|
||||||
cr(html);
|
|
||||||
cmark_strbuf_puts(html, "<table");
|
|
||||||
S_render_sourcepos(node, html, options);
|
|
||||||
cmark_strbuf_putc(html, '>');
|
|
||||||
state->need_closing_table_body = false;
|
|
||||||
} else {
|
|
||||||
if (state->need_closing_table_body)
|
|
||||||
cmark_strbuf_puts(html, "</tbody>");
|
|
||||||
state->need_closing_table_body = false;
|
|
||||||
cmark_strbuf_puts(html, "</table>");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMARK_NODE_TABLE_ROW:
|
|
||||||
if (entering) {
|
|
||||||
cr(html);
|
|
||||||
if (node->as.table_row.is_header) {
|
|
||||||
state->in_table_header = true;
|
|
||||||
cmark_strbuf_puts(html, "<thead>");
|
|
||||||
cr(html);
|
|
||||||
}
|
|
||||||
cmark_strbuf_puts(html, "<tr");
|
|
||||||
S_render_sourcepos(node, html, options);
|
|
||||||
cmark_strbuf_putc(html, '>');
|
|
||||||
} else {
|
|
||||||
cr(html);
|
|
||||||
cmark_strbuf_puts(html, "</tr>");
|
|
||||||
if (node->as.table_row.is_header) {
|
|
||||||
cr(html);
|
|
||||||
cmark_strbuf_puts(html, "</thead>");
|
|
||||||
cr(html);
|
|
||||||
cmark_strbuf_puts(html, "<tbody>");
|
|
||||||
state->need_closing_table_body = true;
|
|
||||||
state->in_table_header = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMARK_NODE_TABLE_CELL:
|
|
||||||
if (entering) {
|
|
||||||
cr(html);
|
|
||||||
if (state->in_table_header) {
|
|
||||||
cmark_strbuf_puts(html, "<th");
|
|
||||||
} else {
|
|
||||||
cmark_strbuf_puts(html, "<td");
|
|
||||||
}
|
|
||||||
S_render_sourcepos(node, html, options);
|
|
||||||
cmark_strbuf_putc(html, '>');
|
|
||||||
} else {
|
|
||||||
if (state->in_table_header) {
|
|
||||||
cmark_strbuf_puts(html, "</th>");
|
|
||||||
} else {
|
|
||||||
cmark_strbuf_puts(html, "</td>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMARK_NODE_TEXT:
|
case CMARK_NODE_TEXT:
|
||||||
escape_html(html, node->as.literal.data, node->as.literal.len);
|
escape_html(html, node->as.literal.data, node->as.literal.len);
|
||||||
break;
|
break;
|
||||||
|
@ -306,7 +273,20 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
if (options & CMARK_OPT_SAFE) {
|
if (options & CMARK_OPT_SAFE) {
|
||||||
cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
|
cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
|
||||||
} else {
|
} else {
|
||||||
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
|
filtered = false;
|
||||||
|
for (it = renderer->filter_extensions; it; it = it->next) {
|
||||||
|
ext = (cmark_syntax_extension *) it->data;
|
||||||
|
if (!ext->html_filter_func(ext, node->as.literal.data, node->as.literal.len)) {
|
||||||
|
filtered = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!filtered) {
|
||||||
|
cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
|
||||||
|
} else {
|
||||||
|
cmark_strbuf_puts(html, "<");
|
||||||
|
cmark_strbuf_put(html, node->as.literal.data + 1, node->as.literal.len - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -363,7 +343,7 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
node->as.link.url.len);
|
node->as.link.url.len);
|
||||||
}
|
}
|
||||||
cmark_strbuf_puts(html, "\" alt=\"");
|
cmark_strbuf_puts(html, "\" alt=\"");
|
||||||
state->plain = node;
|
renderer->plain = node;
|
||||||
} else {
|
} else {
|
||||||
if (node->as.link.title.len) {
|
if (node->as.link.title.len) {
|
||||||
cmark_strbuf_puts(html, "\" title=\"");
|
cmark_strbuf_puts(html, "\" title=\"");
|
||||||
|
@ -374,41 +354,41 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_STRIKETHROUGH:
|
|
||||||
if (entering) {
|
|
||||||
cmark_strbuf_puts(html, "<del>");
|
|
||||||
} else {
|
|
||||||
cmark_strbuf_puts(html, "</del>");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cmark_strbuf_putc(html, 'x');
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *cmark_render_html(cmark_node *root, int options) {
|
char *cmark_render_html(cmark_node *root, int options, cmark_llist *extensions) {
|
||||||
return cmark_render_html_with_mem(root, options, cmark_node_mem(root));
|
return cmark_render_html_with_mem(root, options, extensions, cmark_node_mem(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
char *cmark_render_html_with_mem(cmark_node *root, int options, cmark_mem *mem) {
|
char *cmark_render_html_with_mem(cmark_node *root, int options, cmark_llist *extensions, cmark_mem *mem) {
|
||||||
char *result;
|
char *result;
|
||||||
cmark_strbuf html = CMARK_BUF_INIT(mem);
|
cmark_strbuf html = CMARK_BUF_INIT(mem);
|
||||||
cmark_event_type ev_type;
|
cmark_event_type ev_type;
|
||||||
cmark_node *cur;
|
cmark_node *cur;
|
||||||
struct render_state state = {&html, NULL, false, false};
|
cmark_html_renderer renderer = {&html, NULL, NULL, NULL};
|
||||||
cmark_iter *iter = cmark_iter_new(root);
|
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) {
|
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||||
cur = cmark_iter_get_node(iter);
|
cur = cmark_iter_get_node(iter);
|
||||||
S_render_node(cur, ev_type, &state, options);
|
S_render_node(&renderer, cur, ev_type, options);
|
||||||
}
|
}
|
||||||
result = (char *)cmark_strbuf_detach(&html);
|
result = (char *)cmark_strbuf_detach(&html);
|
||||||
|
|
||||||
|
cmark_llist_free(mem, renderer.filter_extensions);
|
||||||
|
|
||||||
cmark_iter_free(iter);
|
cmark_iter_free(iter);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef CMARK_HTML_H
|
||||||
|
#define CMARK_HTML_H
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
|
CMARK_INLINE
|
||||||
|
static void cmark_html_render_cr(cmark_strbuf *html) {
|
||||||
|
if (html->size && html->ptr[html->size - 1] != '\n')
|
||||||
|
cmark_strbuf_putc(html, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 100
|
||||||
|
|
||||||
|
CMARK_INLINE
|
||||||
|
static void cmark_html_render_sourcepos(cmark_node *node, cmark_strbuf *html, int options) {
|
||||||
|
char buffer[BUFFER_SIZE];
|
||||||
|
if (CMARK_OPT_SOURCEPOS & options) {
|
||||||
|
snprintf(buffer, BUFFER_SIZE, " data-sourcepos=\"%d:%d-%d:%d\"",
|
||||||
|
cmark_node_get_start_line(node), cmark_node_get_start_column(node),
|
||||||
|
cmark_node_get_end_line(node), cmark_node_get_end_column(node));
|
||||||
|
cmark_strbuf_puts(html, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -1105,7 +1105,6 @@ static cmark_node *try_extensions(cmark_parser *parser,
|
||||||
|
|
||||||
for (tmp = parser->inline_syntax_extensions; tmp; tmp = tmp->next) {
|
for (tmp = parser->inline_syntax_extensions; tmp; tmp = tmp->next) {
|
||||||
cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data;
|
cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data;
|
||||||
|
|
||||||
res = ext->match_inline(ext, parser, parent, c, subj);
|
res = ext->match_inline(ext, parser, parent, c, subj);
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
|
@ -1197,10 +1196,10 @@ static int parse_inline(cmark_parser *parser, subject *subj, cmark_node *parent,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse inlines from parent's string_content, adding as children of parent.
|
// Parse inlines from parent's string_content, adding as children of parent.
|
||||||
extern void cmark_parse_inlines(cmark_parser *parser,
|
void cmark_parse_inlines(cmark_parser *parser,
|
||||||
cmark_node *parent,
|
cmark_node *parent,
|
||||||
cmark_reference_map *refmap,
|
cmark_reference_map *refmap,
|
||||||
int options) {
|
int options) {
|
||||||
subject subj;
|
subject subj;
|
||||||
subject_from_buf(parser->mem, &subj, &parent->content, refmap);
|
subject_from_buf(parser->mem, &subj, &parent->content, refmap);
|
||||||
cmark_chunk_rtrim(&subj.input);
|
cmark_chunk_rtrim(&subj.input);
|
||||||
|
@ -1409,6 +1408,35 @@ int cmark_inline_parser_get_offset(cmark_inline_parser *parser) {
|
||||||
return parser->pos;
|
return parser->pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cmark_inline_parser_set_offset(cmark_inline_parser *parser, int offset) {
|
||||||
|
parser->pos = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmark_chunk *cmark_inline_parser_get_chunk(cmark_inline_parser *parser) {
|
||||||
|
return &parser->input;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmark_inline_parser_in_bracket(cmark_inline_parser *parser, int image) {
|
||||||
|
for (bracket *b = parser->last_bracket; b; b = b->previous)
|
||||||
|
if (b->active && b->image == image)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmark_node_unput(cmark_node *node, int n) {
|
||||||
|
node = node->last_child;
|
||||||
|
while (n > 0 && node && node->type == CMARK_NODE_TEXT) {
|
||||||
|
if (node->as.literal.len < n) {
|
||||||
|
n -= node->as.literal.len;
|
||||||
|
node->as.literal.len = 0;
|
||||||
|
} else {
|
||||||
|
node->as.literal.len -= n;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
node = node->prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delimiter *cmark_inline_parser_get_last_delimiter(cmark_inline_parser *parser) {
|
delimiter *cmark_inline_parser_get_last_delimiter(cmark_inline_parser *parser) {
|
||||||
return parser->last_delim;
|
return parser->last_delim;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,12 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "references.h"
|
||||||
|
|
||||||
cmark_chunk cmark_clean_url(cmark_mem *mem, cmark_chunk *url);
|
cmark_chunk cmark_clean_url(cmark_mem *mem, cmark_chunk *url);
|
||||||
cmark_chunk cmark_clean_title(cmark_mem *mem, cmark_chunk *title);
|
cmark_chunk cmark_clean_title(cmark_mem *mem, cmark_chunk *title);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_parse_inlines(cmark_parser *parser,
|
void cmark_parse_inlines(cmark_parser *parser,
|
||||||
cmark_node *parent,
|
cmark_node *parent,
|
||||||
cmark_reference_map *refmap,
|
cmark_reference_map *refmap,
|
||||||
|
|
|
@ -6,12 +6,6 @@
|
||||||
#include "cmark.h"
|
#include "cmark.h"
|
||||||
#include "iterator.h"
|
#include "iterator.h"
|
||||||
|
|
||||||
static const int S_leaf_mask =
|
|
||||||
(1 << CMARK_NODE_HTML_BLOCK) | (1 << CMARK_NODE_THEMATIC_BREAK) |
|
|
||||||
(1 << CMARK_NODE_CODE_BLOCK) | (1 << CMARK_NODE_TEXT) |
|
|
||||||
(1 << CMARK_NODE_SOFTBREAK) | (1 << CMARK_NODE_LINEBREAK) |
|
|
||||||
(1 << CMARK_NODE_CODE) | (1 << CMARK_NODE_HTML_INLINE);
|
|
||||||
|
|
||||||
cmark_iter *cmark_iter_new(cmark_node *root) {
|
cmark_iter *cmark_iter_new(cmark_node *root) {
|
||||||
if (root == NULL) {
|
if (root == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -30,7 +24,18 @@ cmark_iter *cmark_iter_new(cmark_node *root) {
|
||||||
void cmark_iter_free(cmark_iter *iter) { iter->mem->free(iter); }
|
void cmark_iter_free(cmark_iter *iter) { iter->mem->free(iter); }
|
||||||
|
|
||||||
static bool S_is_leaf(cmark_node *node) {
|
static bool S_is_leaf(cmark_node *node) {
|
||||||
return ((1 << node->type) & S_leaf_mask) != 0;
|
switch (node->type) {
|
||||||
|
case CMARK_NODE_HTML_BLOCK:
|
||||||
|
case CMARK_NODE_THEMATIC_BREAK:
|
||||||
|
case CMARK_NODE_CODE_BLOCK:
|
||||||
|
case CMARK_NODE_TEXT:
|
||||||
|
case CMARK_NODE_SOFTBREAK:
|
||||||
|
case CMARK_NODE_LINEBREAK:
|
||||||
|
case CMARK_NODE_CODE:
|
||||||
|
case CMARK_NODE_HTML_INLINE:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmark_event_type cmark_iter_next(cmark_iter *iter) {
|
cmark_event_type cmark_iter_next(cmark_iter *iter) {
|
||||||
|
@ -118,3 +123,36 @@ void cmark_consolidate_text_nodes(cmark_node *root) {
|
||||||
cmark_strbuf_free(&buf);
|
cmark_strbuf_free(&buf);
|
||||||
cmark_iter_free(iter);
|
cmark_iter_free(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cmark_node_own(cmark_node *root) {
|
||||||
|
if (root == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cmark_iter *iter = cmark_iter_new(root);
|
||||||
|
cmark_event_type ev_type;
|
||||||
|
cmark_node *cur;
|
||||||
|
|
||||||
|
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
||||||
|
cur = cmark_iter_get_node(iter);
|
||||||
|
if (ev_type == CMARK_EVENT_ENTER) {
|
||||||
|
switch (cur->type) {
|
||||||
|
case CMARK_NODE_TEXT:
|
||||||
|
case CMARK_NODE_HTML_INLINE:
|
||||||
|
case CMARK_NODE_CODE:
|
||||||
|
case CMARK_NODE_HTML_BLOCK:
|
||||||
|
cmark_chunk_to_cstr(iter->mem, &cur->as.literal);
|
||||||
|
break;
|
||||||
|
case CMARK_NODE_LINK:
|
||||||
|
cmark_chunk_to_cstr(iter->mem, &cur->as.link.url);
|
||||||
|
cmark_chunk_to_cstr(iter->mem, &cur->as.link.title);
|
||||||
|
break;
|
||||||
|
case CMARK_NODE_CUSTOM_INLINE:
|
||||||
|
cmark_chunk_to_cstr(iter->mem, &cur->as.custom.on_enter);
|
||||||
|
cmark_chunk_to_cstr(iter->mem, &cur->as.custom.on_exit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmark_iter_free(iter);
|
||||||
|
}
|
||||||
|
|
54
src/latex.c
54
src/latex.c
|
@ -10,6 +10,7 @@
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
#include "scanners.h"
|
#include "scanners.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
#include "syntax_extension.h"
|
||||||
|
|
||||||
#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
|
#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
|
||||||
#define LIT(s) renderer->out(renderer, s, false, LITERAL)
|
#define LIT(s) renderer->out(renderer, s, false, LITERAL)
|
||||||
|
@ -226,8 +227,10 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||||
cmark_list_type list_type;
|
cmark_list_type list_type;
|
||||||
bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options);
|
bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options);
|
||||||
|
|
||||||
// avoid warning about unused parameter:
|
if (node->extension && node->extension->latex_render_func) {
|
||||||
(void)(options);
|
node->extension->latex_render_func(node->extension, renderer, node, ev_type, options);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case CMARK_NODE_DOCUMENT:
|
case CMARK_NODE_DOCUMENT:
|
||||||
|
@ -346,44 +349,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_TABLE:
|
|
||||||
if (entering) {
|
|
||||||
int i, n_cols;
|
|
||||||
CR();
|
|
||||||
LIT("\\begin{table}");
|
|
||||||
CR();
|
|
||||||
LIT("\\begin{tabular}{");
|
|
||||||
|
|
||||||
n_cols = node->as.table.n_columns;
|
|
||||||
for (i = 0; i < n_cols; i++) {
|
|
||||||
LIT("l");
|
|
||||||
}
|
|
||||||
LIT("}");
|
|
||||||
CR();
|
|
||||||
} else {
|
|
||||||
LIT("\\end{tabular}");
|
|
||||||
CR();
|
|
||||||
LIT("\\end{table}");
|
|
||||||
CR();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMARK_NODE_TABLE_ROW:
|
|
||||||
if (!entering) {
|
|
||||||
CR();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMARK_NODE_TABLE_CELL:
|
|
||||||
if (!entering) {
|
|
||||||
if (node->next) {
|
|
||||||
LIT(" & ");
|
|
||||||
} else {
|
|
||||||
LIT(" \\\\");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMARK_NODE_TEXT:
|
case CMARK_NODE_TEXT:
|
||||||
OUT(cmark_node_get_literal(node), allow_wrap, NORMAL);
|
OUT(cmark_node_get_literal(node), allow_wrap, NORMAL);
|
||||||
break;
|
break;
|
||||||
|
@ -478,15 +443,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_STRIKETHROUGH:
|
|
||||||
/* requires \usepackage{ulem} */
|
|
||||||
if (entering) {
|
|
||||||
LIT("\\sout{");
|
|
||||||
} else {
|
|
||||||
LIT("}");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -6,5 +6,5 @@ includedir=@CMAKE_INSTALL_PREFIX@/include
|
||||||
Name: libcmark
|
Name: libcmark
|
||||||
Description: CommonMark parsing, rendering, and manipulation
|
Description: CommonMark parsing, rendering, and manipulation
|
||||||
Version: @PROJECT_VERSION@
|
Version: @PROJECT_VERSION@
|
||||||
Libs: -L${libdir} -lcmark -ldl
|
Libs: -L${libdir} -lcmark
|
||||||
Cflags: -I${includedir}
|
Cflags: -I${includedir}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
#include "cmark.h"
|
#include "cmark.h"
|
||||||
|
|
||||||
cmark_llist *cmark_llist_append(cmark_llist *head, void *data) {
|
cmark_llist *cmark_llist_append(cmark_mem *mem, cmark_llist *head, void *data) {
|
||||||
cmark_llist *tmp;
|
cmark_llist *tmp;
|
||||||
cmark_llist *new_node = (cmark_llist *) malloc(sizeof(cmark_llist));
|
cmark_llist *new_node = (cmark_llist *) mem->calloc(1, sizeof(cmark_llist));
|
||||||
|
|
||||||
new_node->data = data;
|
new_node->data = data;
|
||||||
new_node->next = NULL;
|
new_node->next = NULL;
|
||||||
|
@ -19,19 +19,19 @@ cmark_llist *cmark_llist_append(cmark_llist *head, void *data) {
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmark_llist_free_full(cmark_llist *head, cmark_free_func free_func) {
|
void cmark_llist_free_full(cmark_mem *mem, cmark_llist *head, cmark_free_func free_func) {
|
||||||
cmark_llist *tmp, *prev;
|
cmark_llist *tmp, *prev;
|
||||||
|
|
||||||
for (tmp = head; tmp;) {
|
for (tmp = head; tmp;) {
|
||||||
if (free_func)
|
if (free_func)
|
||||||
free_func(tmp->data);
|
free_func(mem, tmp->data);
|
||||||
|
|
||||||
prev = tmp;
|
prev = tmp;
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
free(prev);
|
mem->free(prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmark_llist_free(cmark_llist *head) {
|
void cmark_llist_free(cmark_mem *mem, cmark_llist *head) {
|
||||||
cmark_llist_free_full(head, NULL);
|
cmark_llist_free_full(mem, head, NULL);
|
||||||
}
|
}
|
||||||
|
|
21
src/main.c
21
src/main.c
|
@ -8,8 +8,11 @@
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "cmark_extension_api.h"
|
#include "cmark_extension_api.h"
|
||||||
#include "syntax_extension.h"
|
#include "syntax_extension.h"
|
||||||
|
#include "parser.h"
|
||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
|
|
||||||
|
#include "../extensions/core-extensions.h"
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -42,14 +45,14 @@ void print_usage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool print_document(cmark_node *document, writer_format writer,
|
static bool print_document(cmark_node *document, writer_format writer,
|
||||||
int options, int width) {
|
int options, int width, cmark_parser *parser) {
|
||||||
char *result;
|
char *result;
|
||||||
|
|
||||||
cmark_mem *mem = cmark_get_default_mem_allocator();
|
cmark_mem *mem = cmark_get_default_mem_allocator();
|
||||||
|
|
||||||
switch (writer) {
|
switch (writer) {
|
||||||
case FORMAT_HTML:
|
case FORMAT_HTML:
|
||||||
result = cmark_render_html_with_mem(document, options, mem);
|
result = cmark_render_html_with_mem(document, options, parser->syntax_extensions, mem);
|
||||||
break;
|
break;
|
||||||
case FORMAT_XML:
|
case FORMAT_XML:
|
||||||
result = cmark_render_xml_with_mem(document, options, mem);
|
result = cmark_render_xml_with_mem(document, options, mem);
|
||||||
|
@ -68,7 +71,7 @@ static bool print_document(cmark_node *document, writer_format writer,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printf("%s", result);
|
printf("%s", result);
|
||||||
cmark_node_mem(document)->free(result);
|
mem->free(result);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -79,13 +82,14 @@ static void print_extensions(void) {
|
||||||
|
|
||||||
printf ("Available extensions:\n");
|
printf ("Available extensions:\n");
|
||||||
|
|
||||||
syntax_extensions = cmark_list_syntax_extensions();
|
cmark_mem *mem = cmark_get_default_mem_allocator();
|
||||||
|
syntax_extensions = cmark_list_syntax_extensions(mem);
|
||||||
for (tmp = syntax_extensions; tmp; tmp=tmp->next) {
|
for (tmp = syntax_extensions; tmp; tmp=tmp->next) {
|
||||||
cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data;
|
cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data;
|
||||||
printf("%s\n", ext->name);
|
printf("%s\n", ext->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmark_llist_free(syntax_extensions);
|
cmark_llist_free(mem, syntax_extensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
@ -101,6 +105,8 @@ int main(int argc, char *argv[]) {
|
||||||
int options = CMARK_OPT_DEFAULT;
|
int options = CMARK_OPT_DEFAULT;
|
||||||
int res = 1;
|
int res = 1;
|
||||||
|
|
||||||
|
cmark_register_plugin(core_extensions_registration);
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
_setmode(_fileno(stdin), _O_BINARY);
|
_setmode(_fileno(stdin), _O_BINARY);
|
||||||
_setmode(_fileno(stdout), _O_BINARY);
|
_setmode(_fileno(stdout), _O_BINARY);
|
||||||
|
@ -229,10 +235,9 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
document = cmark_parser_finish(parser);
|
document = cmark_parser_finish(parser);
|
||||||
|
|
||||||
if (!print_document(document, writer, options, width))
|
if (!print_document(document, writer, options, width, parser))
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
|
|
||||||
success:
|
success:
|
||||||
res = 0;
|
res = 0;
|
||||||
|
|
||||||
|
@ -247,6 +252,8 @@ failure:
|
||||||
cmark_arena_reset();
|
cmark_arena_reset();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
cmark_release_plugins();
|
||||||
|
|
||||||
free(files);
|
free(files);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
51
src/man.c
51
src/man.c
|
@ -9,6 +9,7 @@
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
#include "syntax_extension.h"
|
||||||
|
|
||||||
#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
|
#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
|
||||||
#define LIT(s) renderer->out(renderer, s, false, LITERAL)
|
#define LIT(s) renderer->out(renderer, s, false, LITERAL)
|
||||||
|
@ -77,8 +78,10 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||||
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
||||||
bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options);
|
bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options);
|
||||||
|
|
||||||
// avoid unused parameter error:
|
if (node->extension && node->extension->man_render_func) {
|
||||||
(void)(options);
|
node->extension->man_render_func(node->extension, renderer, node, ev_type, options);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case CMARK_NODE_DOCUMENT:
|
case CMARK_NODE_DOCUMENT:
|
||||||
|
@ -186,40 +189,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_TABLE:
|
|
||||||
if (entering) {
|
|
||||||
int i, n_cols;
|
|
||||||
CR();
|
|
||||||
LIT(".TS");
|
|
||||||
CR();
|
|
||||||
LIT("tab(@);");
|
|
||||||
CR();
|
|
||||||
|
|
||||||
n_cols = node->as.table.n_columns;
|
|
||||||
|
|
||||||
for (i = 0; i < n_cols; i++) {
|
|
||||||
LIT("c");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n_cols) {
|
|
||||||
LIT(".");
|
|
||||||
CR();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LIT(".TE");
|
|
||||||
CR();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CMARK_NODE_TABLE_ROW:
|
|
||||||
if (!entering) {
|
|
||||||
CR();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CMARK_NODE_TABLE_CELL:
|
|
||||||
if (!entering && node->next) {
|
|
||||||
LIT("@");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CMARK_NODE_TEXT:
|
case CMARK_NODE_TEXT:
|
||||||
OUT(cmark_node_get_literal(node), allow_wrap, NORMAL);
|
OUT(cmark_node_get_literal(node), allow_wrap, NORMAL);
|
||||||
break;
|
break;
|
||||||
|
@ -286,16 +255,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMARK_NODE_STRIKETHROUGH:
|
|
||||||
if (entering) {
|
|
||||||
CR();
|
|
||||||
LIT(".ST \"");
|
|
||||||
} else {
|
|
||||||
LIT("\"");
|
|
||||||
CR();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
|
|
206
src/node.c
206
src/node.c
|
@ -3,25 +3,47 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
#include "syntax_extension.h"
|
||||||
|
|
||||||
static void S_node_unlink(cmark_node *node);
|
static void S_node_unlink(cmark_node *node);
|
||||||
|
|
||||||
#define NODE_MEM(node) cmark_node_mem(node)
|
#define NODE_MEM(node) cmark_node_mem(node)
|
||||||
|
|
||||||
static CMARK_INLINE bool S_is_block(cmark_node *node) {
|
bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) {
|
||||||
if (node == NULL) {
|
if (child_type == CMARK_NODE_DOCUMENT) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return node->type >= CMARK_NODE_FIRST_BLOCK &&
|
|
||||||
node->type <= CMARK_NODE_LAST_BLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CMARK_INLINE bool S_is_inline(cmark_node *node) {
|
if (node->extension && node->extension->can_contain_func) {
|
||||||
if (node == NULL) {
|
return node->extension->can_contain_func(node->extension, node, child_type);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return node->type >= CMARK_NODE_FIRST_INLINE &&
|
|
||||||
node->type <= CMARK_NODE_LAST_INLINE;
|
switch (node->type) {
|
||||||
|
case CMARK_NODE_DOCUMENT:
|
||||||
|
case CMARK_NODE_BLOCK_QUOTE:
|
||||||
|
case CMARK_NODE_ITEM:
|
||||||
|
return CMARK_NODE_TYPE_BLOCK_P(child_type) && child_type != CMARK_NODE_ITEM;
|
||||||
|
|
||||||
|
case CMARK_NODE_LIST:
|
||||||
|
return child_type == CMARK_NODE_ITEM;
|
||||||
|
|
||||||
|
case CMARK_NODE_CUSTOM_BLOCK:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case CMARK_NODE_PARAGRAPH:
|
||||||
|
case CMARK_NODE_HEADING:
|
||||||
|
case CMARK_NODE_EMPH:
|
||||||
|
case CMARK_NODE_STRONG:
|
||||||
|
case CMARK_NODE_LINK:
|
||||||
|
case CMARK_NODE_IMAGE:
|
||||||
|
case CMARK_NODE_CUSTOM_INLINE:
|
||||||
|
return CMARK_NODE_TYPE_INLINE_P(child_type);
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool S_can_contain(cmark_node *node, cmark_node *child) {
|
static bool S_can_contain(cmark_node *node, cmark_node *child) {
|
||||||
|
@ -30,6 +52,9 @@ static bool S_can_contain(cmark_node *node, cmark_node *child) {
|
||||||
if (node == NULL || child == NULL) {
|
if (node == NULL || child == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (NODE_MEM(node) != NODE_MEM(child)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Verify that child is not an ancestor of node or equal to node.
|
// Verify that child is not an ancestor of node or equal to node.
|
||||||
cur = node;
|
cur = node;
|
||||||
|
@ -40,49 +65,7 @@ static bool S_can_contain(cmark_node *node, cmark_node *child) {
|
||||||
cur = cur->parent;
|
cur = cur->parent;
|
||||||
} while (cur != NULL);
|
} while (cur != NULL);
|
||||||
|
|
||||||
if (child->type == CMARK_NODE_DOCUMENT) {
|
return cmark_node_can_contain_type(node, (cmark_node_type) child->type);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (node->type) {
|
|
||||||
case CMARK_NODE_DOCUMENT:
|
|
||||||
case CMARK_NODE_BLOCK_QUOTE:
|
|
||||||
case CMARK_NODE_ITEM:
|
|
||||||
return S_is_block(child) && child->type != CMARK_NODE_ITEM;
|
|
||||||
|
|
||||||
case CMARK_NODE_LIST:
|
|
||||||
return child->type == CMARK_NODE_ITEM;
|
|
||||||
|
|
||||||
case CMARK_NODE_CUSTOM_BLOCK:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case CMARK_NODE_PARAGRAPH:
|
|
||||||
case CMARK_NODE_HEADING:
|
|
||||||
case CMARK_NODE_EMPH:
|
|
||||||
case CMARK_NODE_STRONG:
|
|
||||||
case CMARK_NODE_LINK:
|
|
||||||
case CMARK_NODE_IMAGE:
|
|
||||||
case CMARK_NODE_STRIKETHROUGH:
|
|
||||||
case CMARK_NODE_CUSTOM_INLINE:
|
|
||||||
return S_is_inline(child);
|
|
||||||
case CMARK_NODE_TABLE:
|
|
||||||
return child->type == CMARK_NODE_TABLE_ROW;
|
|
||||||
case CMARK_NODE_TABLE_ROW:
|
|
||||||
return child->type == CMARK_NODE_TABLE_CELL;
|
|
||||||
case CMARK_NODE_TABLE_CELL:
|
|
||||||
return child->type == CMARK_NODE_TEXT ||
|
|
||||||
child->type == CMARK_NODE_CODE ||
|
|
||||||
child->type == CMARK_NODE_EMPH ||
|
|
||||||
child->type == CMARK_NODE_STRONG ||
|
|
||||||
child->type == CMARK_NODE_LINK ||
|
|
||||||
child->type == CMARK_NODE_IMAGE ||
|
|
||||||
child->type == CMARK_NODE_STRIKETHROUGH;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmark_node *cmark_node_new_with_mem(cmark_node_type type, cmark_mem *mem) {
|
cmark_node *cmark_node_new_with_mem(cmark_node_type type, cmark_mem *mem) {
|
||||||
|
@ -117,29 +100,29 @@ cmark_node *cmark_node_new(cmark_node_type type) {
|
||||||
|
|
||||||
static void free_node_as(cmark_node *node) {
|
static void free_node_as(cmark_node *node) {
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case CMARK_NODE_CODE_BLOCK:
|
case CMARK_NODE_CODE_BLOCK:
|
||||||
cmark_chunk_free(NODE_MEM(node), &node->as.code.info);
|
cmark_chunk_free(NODE_MEM(node), &node->as.code.info);
|
||||||
cmark_chunk_free(NODE_MEM(node), &node->as.code.literal);
|
cmark_chunk_free(NODE_MEM(node), &node->as.code.literal);
|
||||||
break;
|
break;
|
||||||
case CMARK_NODE_TEXT:
|
case CMARK_NODE_TEXT:
|
||||||
case CMARK_NODE_HTML_INLINE:
|
case CMARK_NODE_HTML_INLINE:
|
||||||
case CMARK_NODE_CODE:
|
case CMARK_NODE_CODE:
|
||||||
case CMARK_NODE_HTML_BLOCK:
|
case CMARK_NODE_HTML_BLOCK:
|
||||||
cmark_chunk_free(NODE_MEM(node), &node->as.literal);
|
cmark_chunk_free(NODE_MEM(node), &node->as.literal);
|
||||||
break;
|
break;
|
||||||
case CMARK_NODE_LINK:
|
case CMARK_NODE_LINK:
|
||||||
case CMARK_NODE_IMAGE:
|
case CMARK_NODE_IMAGE:
|
||||||
cmark_chunk_free(NODE_MEM(node), &node->as.link.url);
|
cmark_chunk_free(NODE_MEM(node), &node->as.link.url);
|
||||||
cmark_chunk_free(NODE_MEM(node), &node->as.link.title);
|
cmark_chunk_free(NODE_MEM(node), &node->as.link.title);
|
||||||
break;
|
break;
|
||||||
case CMARK_NODE_CUSTOM_BLOCK:
|
case CMARK_NODE_CUSTOM_BLOCK:
|
||||||
case CMARK_NODE_CUSTOM_INLINE:
|
case CMARK_NODE_CUSTOM_INLINE:
|
||||||
cmark_chunk_free(NODE_MEM(node), &node->as.custom.on_enter);
|
cmark_chunk_free(NODE_MEM(node), &node->as.custom.on_enter);
|
||||||
cmark_chunk_free(NODE_MEM(node), &node->as.custom.on_exit);
|
cmark_chunk_free(NODE_MEM(node), &node->as.custom.on_exit);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free a cmark_node list and any children.
|
// Free a cmark_node list and any children.
|
||||||
|
@ -149,7 +132,7 @@ static void S_free_nodes(cmark_node *e) {
|
||||||
cmark_strbuf_free(&e->content);
|
cmark_strbuf_free(&e->content);
|
||||||
|
|
||||||
if (e->user_data && e->user_data_free_func)
|
if (e->user_data && e->user_data_free_func)
|
||||||
e->user_data_free_func(e->user_data);
|
e->user_data_free_func(NODE_MEM(e), e->user_data);
|
||||||
|
|
||||||
free_node_as(e);
|
free_node_as(e);
|
||||||
|
|
||||||
|
@ -184,7 +167,7 @@ int cmark_node_set_type(cmark_node * node, cmark_node_type type) {
|
||||||
if (type == node->type)
|
if (type == node->type)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
initial_type = node->type;
|
initial_type = (cmark_node_type) node->type;
|
||||||
node->type = type;
|
node->type = type;
|
||||||
|
|
||||||
if (!S_can_contain(node->parent, node)) {
|
if (!S_can_contain(node->parent, node)) {
|
||||||
|
@ -206,6 +189,10 @@ const char *cmark_node_get_type_string(cmark_node *node) {
|
||||||
return "NONE";
|
return "NONE";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->extension && node->extension->get_type_string_func) {
|
||||||
|
return node->extension->get_type_string_func(node->extension, node);
|
||||||
|
}
|
||||||
|
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case CMARK_NODE_NONE:
|
case CMARK_NODE_NONE:
|
||||||
return "none";
|
return "none";
|
||||||
|
@ -223,15 +210,6 @@ const char *cmark_node_get_type_string(cmark_node *node) {
|
||||||
return "html_block";
|
return "html_block";
|
||||||
case CMARK_NODE_CUSTOM_BLOCK:
|
case CMARK_NODE_CUSTOM_BLOCK:
|
||||||
return "custom_block";
|
return "custom_block";
|
||||||
case CMARK_NODE_TABLE:
|
|
||||||
return "table";
|
|
||||||
case CMARK_NODE_TABLE_ROW:
|
|
||||||
if (node->as.table_row.is_header)
|
|
||||||
return "table_header";
|
|
||||||
else
|
|
||||||
return "table_row";
|
|
||||||
case CMARK_NODE_TABLE_CELL:
|
|
||||||
return "table_cell";
|
|
||||||
case CMARK_NODE_PARAGRAPH:
|
case CMARK_NODE_PARAGRAPH:
|
||||||
return "paragraph";
|
return "paragraph";
|
||||||
case CMARK_NODE_HEADING:
|
case CMARK_NODE_HEADING:
|
||||||
|
@ -258,8 +236,6 @@ const char *cmark_node_get_type_string(cmark_node *node) {
|
||||||
return "link";
|
return "link";
|
||||||
case CMARK_NODE_IMAGE:
|
case CMARK_NODE_IMAGE:
|
||||||
return "image";
|
return "image";
|
||||||
case CMARK_NODE_STRIKETHROUGH:
|
|
||||||
return "strikethrough";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "<unknown>";
|
return "<unknown>";
|
||||||
|
@ -760,68 +736,6 @@ int cmark_node_get_end_column(cmark_node *node) {
|
||||||
return node->end_column;
|
return node->end_column;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmark_node_get_n_table_columns(cmark_node *node) {
|
|
||||||
if (node == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (node->type) {
|
|
||||||
case CMARK_NODE_TABLE:
|
|
||||||
return node->as.table.n_columns;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cmark_node_set_n_table_columns(cmark_node *node, int n_columns) {
|
|
||||||
if (node == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (node->type) {
|
|
||||||
case CMARK_NODE_TABLE:
|
|
||||||
node->as.table.n_columns = n_columns;
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cmark_node_is_table_header(cmark_node *node) {
|
|
||||||
if (node == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (node->type) {
|
|
||||||
case CMARK_NODE_TABLE_ROW:
|
|
||||||
return node->as.table_row.is_header;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cmark_node_set_is_table_header(cmark_node *node, int is_table_header) {
|
|
||||||
if (node == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (node->type) {
|
|
||||||
case CMARK_NODE_TABLE_ROW:
|
|
||||||
node->as.table_row.is_header = is_table_header;
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlink a node without adjusting its next, prev, and parent pointers.
|
// Unlink a node without adjusting its next, prev, and parent pointers.
|
||||||
static void S_node_unlink(cmark_node *node) {
|
static void S_node_unlink(cmark_node *node) {
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
|
|
29
src/node.h
29
src/node.h
|
@ -47,14 +47,6 @@ typedef struct {
|
||||||
cmark_chunk on_exit;
|
cmark_chunk on_exit;
|
||||||
} cmark_custom;
|
} cmark_custom;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int n_columns;
|
|
||||||
} cmark_table;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool is_header;
|
|
||||||
} cmark_table_row;
|
|
||||||
|
|
||||||
enum cmark_node__internal_flags {
|
enum cmark_node__internal_flags {
|
||||||
CMARK_NODE__OPEN = (1 << 0),
|
CMARK_NODE__OPEN = (1 << 0),
|
||||||
CMARK_NODE__LAST_LINE_BLANK = (1 << 1),
|
CMARK_NODE__LAST_LINE_BLANK = (1 << 1),
|
||||||
|
@ -88,9 +80,8 @@ struct cmark_node {
|
||||||
cmark_heading heading;
|
cmark_heading heading;
|
||||||
cmark_link link;
|
cmark_link link;
|
||||||
cmark_custom custom;
|
cmark_custom custom;
|
||||||
cmark_table table;
|
|
||||||
cmark_table_row table_row;
|
|
||||||
int html_block_type;
|
int html_block_type;
|
||||||
|
void *opaque;
|
||||||
} as;
|
} as;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,6 +90,24 @@ static CMARK_INLINE cmark_mem *cmark_node_mem(cmark_node *node) {
|
||||||
}
|
}
|
||||||
CMARK_EXPORT int cmark_node_check(cmark_node *node, FILE *out);
|
CMARK_EXPORT int cmark_node_check(cmark_node *node, FILE *out);
|
||||||
|
|
||||||
|
static CMARK_INLINE bool CMARK_NODE_TYPE_BLOCK_P(cmark_node_type node_type) {
|
||||||
|
return (node_type & CMARK_NODE_TYPE_MASK) == CMARK_NODE_TYPE_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CMARK_INLINE bool CMARK_NODE_BLOCK_P(cmark_node *node) {
|
||||||
|
return node != NULL && CMARK_NODE_TYPE_BLOCK_P((cmark_node_type) node->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CMARK_INLINE bool CMARK_NODE_TYPE_INLINE_P(cmark_node_type node_type) {
|
||||||
|
return (node_type & CMARK_NODE_TYPE_MASK) == CMARK_NODE_TYPE_INLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CMARK_INLINE bool CMARK_NODE_INLINE_P(cmark_node *node) {
|
||||||
|
return node != NULL && CMARK_NODE_TYPE_INLINE_P((cmark_node_type) node->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
CMARK_EXPORT bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef CMARK_AST_H
|
#ifndef CMARK_PARSER_H
|
||||||
#define CMARK_AST_H
|
#define CMARK_PARSER_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
|
11
src/plugin.c
11
src/plugin.c
|
@ -2,15 +2,17 @@
|
||||||
|
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
|
extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;
|
||||||
|
|
||||||
int cmark_plugin_register_syntax_extension(cmark_plugin * plugin,
|
int cmark_plugin_register_syntax_extension(cmark_plugin * plugin,
|
||||||
cmark_syntax_extension * extension) {
|
cmark_syntax_extension * extension) {
|
||||||
plugin->syntax_extensions = cmark_llist_append(plugin->syntax_extensions, extension);
|
plugin->syntax_extensions = cmark_llist_append(&CMARK_DEFAULT_MEM_ALLOCATOR, plugin->syntax_extensions, extension);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmark_plugin *
|
cmark_plugin *
|
||||||
cmark_plugin_new(void) {
|
cmark_plugin_new(void) {
|
||||||
cmark_plugin *res = malloc(sizeof(cmark_plugin));
|
cmark_plugin *res = (cmark_plugin *) CMARK_DEFAULT_MEM_ALLOCATOR.calloc(1, sizeof(cmark_plugin));
|
||||||
|
|
||||||
res->syntax_extensions = NULL;
|
res->syntax_extensions = NULL;
|
||||||
|
|
||||||
|
@ -19,9 +21,10 @@ cmark_plugin_new(void) {
|
||||||
|
|
||||||
void
|
void
|
||||||
cmark_plugin_free(cmark_plugin *plugin) {
|
cmark_plugin_free(cmark_plugin *plugin) {
|
||||||
cmark_llist_free_full(plugin->syntax_extensions,
|
cmark_llist_free_full(&CMARK_DEFAULT_MEM_ALLOCATOR,
|
||||||
|
plugin->syntax_extensions,
|
||||||
(cmark_free_func) cmark_syntax_extension_free);
|
(cmark_free_func) cmark_syntax_extension_free);
|
||||||
free(plugin);
|
CMARK_DEFAULT_MEM_ALLOCATOR.free(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmark_llist *
|
cmark_llist *
|
||||||
|
|
116
src/registry.c
116
src/registry.c
|
@ -1,5 +1,3 @@
|
||||||
#include <dirent.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -10,121 +8,45 @@
|
||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
|
extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;
|
||||||
|
|
||||||
static cmark_llist *syntax_extensions = NULL;
|
static cmark_llist *syntax_extensions = NULL;
|
||||||
static cmark_llist *plugin_handles = NULL;
|
|
||||||
|
|
||||||
static cmark_plugin *scan_file(char* filename) {
|
void cmark_register_plugin(cmark_plugin_init_func reg_fn) {
|
||||||
char* last_slash = strrchr(filename, '/');
|
cmark_plugin *plugin = cmark_plugin_new();
|
||||||
char* name_start = last_slash ? last_slash + 1 : filename;
|
|
||||||
char* last_dot = strrchr(filename, '.');
|
|
||||||
cmark_plugin *plugin = NULL;
|
|
||||||
char *init_func_name = NULL;
|
|
||||||
int i;
|
|
||||||
void *libhandle;
|
|
||||||
char *libname = NULL;
|
|
||||||
|
|
||||||
if (!last_dot || strcmp(last_dot, ".so"))
|
if (!reg_fn(plugin)) {
|
||||||
goto done;
|
cmark_plugin_free(plugin);
|
||||||
|
|
||||||
libname = malloc(sizeof(char) * (strlen(EXTENSION_DIR) + strlen(filename) + 2));
|
|
||||||
snprintf(libname, strlen(EXTENSION_DIR) + strlen(filename) + 2, "%s/%s",
|
|
||||||
EXTENSION_DIR, filename);
|
|
||||||
libhandle = dlopen(libname, RTLD_NOW);
|
|
||||||
free(libname);
|
|
||||||
|
|
||||||
if (!libhandle) {
|
|
||||||
printf("Error loading DSO: %s\n", dlerror());
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
name_start[last_dot - name_start] = '\0';
|
|
||||||
|
|
||||||
for (i = 0; name_start[i]; i++) {
|
|
||||||
if (name_start[i] == '-')
|
|
||||||
name_start[i] = '_';
|
|
||||||
}
|
|
||||||
|
|
||||||
init_func_name = malloc(sizeof(char) * (strlen(name_start) + 6));
|
|
||||||
|
|
||||||
snprintf(init_func_name, strlen(name_start) + 6, "init_%s", name_start);
|
|
||||||
|
|
||||||
cmark_plugin_init_func initfunc = (cmark_plugin_init_func)
|
|
||||||
(intptr_t) dlsym(libhandle, init_func_name);
|
|
||||||
free(init_func_name);
|
|
||||||
|
|
||||||
plugin = cmark_plugin_new();
|
|
||||||
|
|
||||||
if (initfunc) {
|
|
||||||
if (initfunc(plugin)) {
|
|
||||||
plugin_handles = cmark_llist_append(plugin_handles, libhandle);
|
|
||||||
} else {
|
|
||||||
cmark_plugin_free(plugin);
|
|
||||||
printf("Error Initializing plugin %s\n", name_start);
|
|
||||||
plugin = NULL;
|
|
||||||
dlclose(libhandle);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printf("Error loading init function: %s\n", dlerror());
|
|
||||||
dlclose(libhandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scan_path(char *path) {
|
|
||||||
DIR *dir = opendir(path);
|
|
||||||
struct dirent* direntry;
|
|
||||||
|
|
||||||
if (!dir)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while ((direntry = readdir(dir))) {
|
|
||||||
cmark_plugin *plugin = scan_file(direntry->d_name);
|
|
||||||
if (plugin) {
|
|
||||||
cmark_llist *syntax_extensions_list = cmark_plugin_steal_syntax_extensions(plugin);
|
|
||||||
cmark_llist *tmp;
|
|
||||||
|
|
||||||
for (tmp = syntax_extensions_list; tmp; tmp=tmp->next) {
|
|
||||||
syntax_extensions = cmark_llist_append(syntax_extensions, tmp->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
cmark_llist_free(syntax_extensions_list);
|
|
||||||
cmark_plugin_free(plugin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
cmark_llist *syntax_extensions_list = cmark_plugin_steal_syntax_extensions(plugin),
|
||||||
}
|
*it;
|
||||||
|
|
||||||
void cmark_discover_plugins(void) {
|
for (it = syntax_extensions_list; it; it = it->next) {
|
||||||
cmark_release_plugins();
|
syntax_extensions = cmark_llist_append(&CMARK_DEFAULT_MEM_ALLOCATOR, syntax_extensions, it->data);
|
||||||
scan_path(EXTENSION_DIR);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
cmark_llist_free(&CMARK_DEFAULT_MEM_ALLOCATOR, syntax_extensions_list);
|
||||||
release_plugin_handle(void *libhandle) {
|
cmark_plugin_free(plugin);
|
||||||
dlclose(libhandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmark_release_plugins(void) {
|
void cmark_release_plugins(void) {
|
||||||
if (syntax_extensions) {
|
if (syntax_extensions) {
|
||||||
cmark_llist_free_full(syntax_extensions,
|
cmark_llist_free_full(
|
||||||
|
&CMARK_DEFAULT_MEM_ALLOCATOR,
|
||||||
|
syntax_extensions,
|
||||||
(cmark_free_func) cmark_syntax_extension_free);
|
(cmark_free_func) cmark_syntax_extension_free);
|
||||||
syntax_extensions = NULL;
|
syntax_extensions = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmark_llist_free_full(plugin_handles, release_plugin_handle);
|
|
||||||
plugin_handles = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmark_llist *cmark_list_syntax_extensions(void) {
|
cmark_llist *cmark_list_syntax_extensions(cmark_mem *mem) {
|
||||||
cmark_llist *tmp;
|
cmark_llist *it;
|
||||||
cmark_llist *res = NULL;
|
cmark_llist *res = NULL;
|
||||||
|
|
||||||
for (tmp = syntax_extensions; tmp; tmp = tmp->next) {
|
for (it = syntax_extensions; it; it = it->next) {
|
||||||
res = cmark_llist_append(res, tmp->data);
|
res = cmark_llist_append(mem, res, it->data);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,16 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "cmark.h"
|
#include "cmark.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
|
||||||
void cmark_discover_plugins(void);
|
CMARK_EXPORT
|
||||||
|
void cmark_register_plugin(cmark_plugin_init_func reg_fn);
|
||||||
|
|
||||||
|
CMARK_EXPORT
|
||||||
void cmark_release_plugins(void);
|
void cmark_release_plugins(void);
|
||||||
cmark_llist *cmark_list_syntax_extensions(void);
|
|
||||||
|
CMARK_EXPORT
|
||||||
|
cmark_llist *cmark_list_syntax_extensions(cmark_mem *mem);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,15 @@ struct cmark_renderer {
|
||||||
|
|
||||||
typedef struct cmark_renderer cmark_renderer;
|
typedef struct cmark_renderer cmark_renderer;
|
||||||
|
|
||||||
|
struct cmark_html_renderer {
|
||||||
|
cmark_strbuf *html;
|
||||||
|
cmark_node *plain;
|
||||||
|
cmark_llist *filter_extensions;
|
||||||
|
void *opaque;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct cmark_html_renderer cmark_html_renderer;
|
||||||
|
|
||||||
void cmark_render_ascii(cmark_renderer *renderer, const char *s);
|
void cmark_render_ascii(cmark_renderer *renderer, const char *s);
|
||||||
|
|
||||||
void cmark_render_code_point(cmark_renderer *renderer, uint32_t c);
|
void cmark_render_code_point(cmark_renderer *renderer, uint32_t c);
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#ifndef CMARK_SCANNERS_H
|
||||||
|
#define CMARK_SCANNERS_H
|
||||||
|
|
||||||
#include "cmark.h"
|
#include "cmark.h"
|
||||||
#include "chunk.h"
|
#include "chunk.h"
|
||||||
|
|
||||||
|
@ -53,3 +56,5 @@ bufsize_t _scan_dangerous_url(const unsigned char *p);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -4,23 +4,38 @@
|
||||||
#include "syntax_extension.h"
|
#include "syntax_extension.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
void cmark_syntax_extension_free(cmark_syntax_extension *extension) {
|
extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;
|
||||||
|
|
||||||
|
static cmark_mem *_mem = &CMARK_DEFAULT_MEM_ALLOCATOR;
|
||||||
|
|
||||||
|
void cmark_syntax_extension_free(cmark_mem *mem, cmark_syntax_extension *extension) {
|
||||||
if (extension->free_function && extension->priv) {
|
if (extension->free_function && extension->priv) {
|
||||||
extension->free_function(extension->priv);
|
extension->free_function(mem, extension->priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmark_llist_free(extension->special_inline_chars);
|
cmark_llist_free(mem, extension->special_inline_chars);
|
||||||
free(extension->name);
|
mem->free(extension->name);
|
||||||
free(extension);
|
mem->free(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmark_syntax_extension *cmark_syntax_extension_new(const char *name) {
|
cmark_syntax_extension *cmark_syntax_extension_new(const char *name) {
|
||||||
cmark_syntax_extension *res = (cmark_syntax_extension *) calloc(1, sizeof(cmark_syntax_extension));
|
cmark_syntax_extension *res = (cmark_syntax_extension *) _mem->calloc(1, sizeof(cmark_syntax_extension));
|
||||||
res->name = (char *) malloc(sizeof(char) * (strlen(name)) + 1);
|
res->name = (char *) _mem->calloc(1, sizeof(char) * (strlen(name)) + 1);
|
||||||
strcpy(res->name, name);
|
strcpy(res->name, name);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmark_node_type cmark_syntax_extension_add_node(int is_inline) {
|
||||||
|
cmark_node_type *ref = !is_inline ? &CMARK_NODE_LAST_BLOCK : &CMARK_NODE_LAST_INLINE;
|
||||||
|
|
||||||
|
if ((*ref & CMARK_NODE_VALUE_MASK) == CMARK_NODE_VALUE_MASK) {
|
||||||
|
assert(false);
|
||||||
|
return (cmark_node_type) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ref = (cmark_node_type) ((int) *ref + 1);
|
||||||
|
}
|
||||||
|
|
||||||
void cmark_syntax_extension_set_open_block_func(cmark_syntax_extension *extension,
|
void cmark_syntax_extension_set_open_block_func(cmark_syntax_extension *extension,
|
||||||
cmark_open_block_func func) {
|
cmark_open_block_func func) {
|
||||||
extension->try_opening_block = func;
|
extension->try_opening_block = func;
|
||||||
|
@ -46,6 +61,51 @@ void cmark_syntax_extension_set_special_inline_chars(cmark_syntax_extension *ext
|
||||||
extension->special_inline_chars = special_chars;
|
extension->special_inline_chars = special_chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cmark_syntax_extension_set_get_type_string_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_get_type_string_func func) {
|
||||||
|
extension->get_type_string_func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmark_syntax_extension_set_can_contain_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_can_contain_func func) {
|
||||||
|
extension->can_contain_func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmark_syntax_extension_set_contains_inlines_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_contains_inlines_func func) {
|
||||||
|
extension->contains_inlines_func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmark_syntax_extension_set_commonmark_render_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_common_render_func func) {
|
||||||
|
extension->commonmark_render_func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmark_syntax_extension_set_latex_render_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_common_render_func func) {
|
||||||
|
extension->latex_render_func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmark_syntax_extension_set_man_render_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_common_render_func func) {
|
||||||
|
extension->man_render_func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmark_syntax_extension_set_html_render_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_html_render_func func) {
|
||||||
|
extension->html_render_func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmark_syntax_extension_set_html_filter_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_html_filter_func func) {
|
||||||
|
extension->html_filter_func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmark_syntax_extension_set_postprocess_func(cmark_syntax_extension *extension,
|
||||||
|
cmark_postprocess_func func) {
|
||||||
|
extension->postprocess_func = func;
|
||||||
|
}
|
||||||
|
|
||||||
void cmark_syntax_extension_set_private(cmark_syntax_extension *extension,
|
void cmark_syntax_extension_set_private(cmark_syntax_extension *extension,
|
||||||
void *priv,
|
void *priv,
|
||||||
cmark_free_func free_func) {
|
cmark_free_func free_func) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef SYNTAX_EXTENSION_H
|
#ifndef CMARK_SYNTAX_EXTENSION_H
|
||||||
#define SYNTAX_EXTENSION_H
|
#define CMARK_SYNTAX_EXTENSION_H
|
||||||
|
|
||||||
#include "cmark.h"
|
#include "cmark.h"
|
||||||
#include "cmark_extension_api.h"
|
#include "cmark_extension_api.h"
|
||||||
|
@ -13,6 +13,15 @@ struct cmark_syntax_extension {
|
||||||
char * name;
|
char * name;
|
||||||
void * priv;
|
void * priv;
|
||||||
cmark_free_func free_function;
|
cmark_free_func free_function;
|
||||||
|
cmark_get_type_string_func get_type_string_func;
|
||||||
|
cmark_can_contain_func can_contain_func;
|
||||||
|
cmark_contains_inlines_func contains_inlines_func;
|
||||||
|
cmark_common_render_func commonmark_render_func;
|
||||||
|
cmark_common_render_func latex_render_func;
|
||||||
|
cmark_common_render_func man_render_func;
|
||||||
|
cmark_html_render_func html_render_func;
|
||||||
|
cmark_html_filter_func html_filter_func;
|
||||||
|
cmark_postprocess_func postprocess_func;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -54,7 +54,6 @@ for entity, utf8 in entities:
|
||||||
print(entity, '[ERRORED (return code {})]'.format(rc))
|
print(entity, '[ERRORED (return code {})]'.format(rc))
|
||||||
print(err)
|
print(err)
|
||||||
elif check in actual:
|
elif check in actual:
|
||||||
print(entity, '[PASSED]')
|
|
||||||
passed += 1
|
passed += 1
|
||||||
else:
|
else:
|
||||||
print(entity, '[FAILED]')
|
print(entity, '[FAILED]')
|
||||||
|
|
|
@ -9,7 +9,7 @@ SET(CMAKE_RC_COMPILER i586-mingw32msvc-windres)
|
||||||
# here is the target environment located
|
# here is the target environment located
|
||||||
SET(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc "${CMAKE_SOURCE_DIR}/windows")
|
SET(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc "${CMAKE_SOURCE_DIR}/windows")
|
||||||
|
|
||||||
# adjust the default behaviour of the FIND_XXX() commands:
|
# adjust the default behaviour of the FIND_XYZ() commands:
|
||||||
# search headers and libraries in the target environment, search
|
# search headers and libraries in the target environment, search
|
||||||
# programs in the host environment
|
# programs in the host environment
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче