Strip extensions API down and separate from core

This commit is contained in:
Yuki Izumi 2016-12-01 14:16:12 +11:00 коммит произвёл Yuki Izumi
Родитель c8960d74de
Коммит 3e3761a26e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 44A3D2C95E26BB14
42 изменённых файлов: 843 добавлений и 1730 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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;
} }

Просмотреть файл

@ -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

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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 {

Просмотреть файл

@ -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, "&lt;");
}
++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, "&lt;");
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;
} }

27
src/html.h Normal file
Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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);
} }

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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"

Просмотреть файл

@ -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 *

Просмотреть файл

@ -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)