From 3e3761a26e68b2319738bbdd49a303a1d6098533 Mon Sep 17 00:00:00 2001 From: Yuki Izumi Date: Thu, 1 Dec 2016 14:16:12 +1100 Subject: [PATCH] Strip extensions API down and separate from core --- Makefile | 17 +- api_test/main.c | 53 ++-- extensions/CMakeLists.txt | 58 +++- extensions/core-extensions.c | 326 +------------------ extensions/core-extensions.h | 16 + extensions/ext_scanners.c | 585 ----------------------------------- extensions/ext_scanners.h | 20 -- extensions/ext_scanners.re | 65 ---- man/man3/cmark.3 | 48 ++- src/CMakeLists.txt | 8 +- src/blocks.c | 60 ++-- src/buffer.h | 36 +++ src/cmark.c | 15 +- src/cmark.h | 102 +++--- src/cmark_ctype.h | 7 + src/cmark_extension_api.h | 123 +++++++- src/commonmark.c | 40 +-- src/config.h.in | 2 - src/houdini.h | 18 +- src/houdini_html_e.c | 2 +- src/html.c | 230 +++++++------- src/html.h | 27 ++ src/inlines.c | 38 ++- src/inlines.h | 3 + src/iterator.c | 52 +++- src/latex.c | 54 +--- src/libcmark.pc.in | 2 +- src/linked_list.c | 14 +- src/main.c | 21 +- src/man.c | 51 +-- src/node.c | 206 ++++-------- src/node.h | 29 +- src/parser.h | 4 +- src/plugin.c | 11 +- src/registry.c | 116 ++----- src/registry.h | 10 +- src/render.h | 9 + src/scanners.h | 5 + src/syntax_extension.c | 74 ++++- src/syntax_extension.h | 13 +- test/entity_tests.py | 1 - toolchain-mingw32.cmake | 2 +- 42 files changed, 843 insertions(+), 1730 deletions(-) create mode 100644 extensions/core-extensions.h delete mode 100644 extensions/ext_scanners.c delete mode 100644 extensions/ext_scanners.h delete mode 100644 extensions/ext_scanners.re create mode 100644 src/html.h diff --git a/Makefile b/Makefile index 6484ee00..e6a88956 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,4 @@ SRCDIR=src -EXTDIR=extensions DATADIR=data BUILDDIR?=build GENERATOR?=Unix Makefiles @@ -127,19 +126,6 @@ $(SRCDIR)/scanners.c: $(SRCDIR)/scanners.re --encoding-policy substitute -o $@ $< $(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 # doesn't need to be regenerated: $(SRCDIR)/entities.inc: tools/make_entities_inc.py @@ -203,6 +189,9 @@ newbench: format: $(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 $< < $(BENCHFILE) > /dev/null diff --git a/api_test/main.c b/api_test/main.c index d7202343..a95abc31 100644 --- a/api_test/main.c +++ b/api_test/main.c @@ -24,7 +24,7 @@ static void test_md_to_html(test_batch_runner *runner, const char *markdown, const char *expected_html, const char *msg); 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, const char *msg); @@ -177,7 +177,7 @@ static void accessors(test_batch_runner *runner) { OK(runner, cmark_node_set_literal(string, literal + sizeof("prefix")), "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[] = "

Header

\n" "
    \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[] = "

    a c

    \n" "

    a c

    \n"; 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"); 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, "

    Hello, world!

    \n", "render_html"); free(html); @@ -375,7 +375,7 @@ static void create_tree(test_batch_runner *runner) { 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, "

    brzz!

    \n", "render_html after shuffling"); 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)"); 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, "

    \n CMARK_NODE_LAST_INLINE - ? CMARK_NODE_LAST_BLOCK - : CMARK_NODE_LAST_INLINE; - OK(runner, max_node_type < 32, "all node types < 32"); - - int list_item_flag = 1 << CMARK_NODE_ITEM; - int top_level_blocks = - (1 << CMARK_NODE_BLOCK_QUOTE) | (1 << CMARK_NODE_LIST) | - (1 << CMARK_NODE_CODE_BLOCK) | (1 << CMARK_NODE_HTML_BLOCK) | - (1 << CMARK_NODE_PARAGRAPH) | (1 << CMARK_NODE_HEADING) | - (1 << CMARK_NODE_THEMATIC_BREAK); - int all_inlines = (1 << CMARK_NODE_TEXT) | (1 << CMARK_NODE_SOFTBREAK) | - (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); + unsigned int list_item_flag[] = {CMARK_NODE_ITEM, 0}; + unsigned int top_level_blocks[] = { + CMARK_NODE_BLOCK_QUOTE, CMARK_NODE_LIST, + CMARK_NODE_CODE_BLOCK, CMARK_NODE_HTML_BLOCK, + CMARK_NODE_PARAGRAPH, CMARK_NODE_HEADING, + CMARK_NODE_THEMATIC_BREAK, 0}; + unsigned int all_inlines[] = { + CMARK_NODE_TEXT, CMARK_NODE_SOFTBREAK, + CMARK_NODE_LINEBREAK, CMARK_NODE_CODE, + CMARK_NODE_HTML_INLINE, CMARK_NODE_EMPH, + CMARK_NODE_STRONG, CMARK_NODE_LINK, + CMARK_NODE_IMAGE, 0}; test_content(runner, CMARK_NODE_DOCUMENT, 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, - int allowed_content) { + unsigned int *allowed_content) { cmark_node *node = cmark_node_new(type); 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); 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); @@ -505,17 +504,17 @@ static void render_html(test_batch_runner *runner) { cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT); 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, "

    foo bar

    \n", "render single paragraph"); free(html); 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"); free(html); 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, "bar", "render inline with children"); free(html); diff --git a/extensions/CMakeLists.txt b/extensions/CMakeLists.txt index 85d9e445..f13818a5 100644 --- a/extensions/CMakeLists.txt +++ b/extensions/CMakeLists.txt @@ -1,11 +1,7 @@ cmake_minimum_required(VERSION 2.8) -set(LIBRARY "cmarkextensions") +set(STATICLIBRARY "libcmarkextensions_static") set(LIBRARY_SOURCES - ${PROJECT_SOURCE_DIR}/src/buffer.c - ${PROJECT_SOURCE_DIR}/src/cmark_ctype.c core-extensions.c - ext_scanners.c - ext_scanners.h ) include_directories( @@ -27,6 +23,54 @@ include_directories(. ${CMAKE_CURRENT_BINARY_DIR}) set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_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() diff --git a/extensions/core-extensions.c b/extensions/core-extensions.c index ad971563..cf7f9f62 100644 --- a/extensions/core-extensions.c +++ b/extensions/core-extensions.c @@ -1,325 +1,3 @@ -#include -#include +#include "core-extensions.h" -#include -#include - -#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; -} +int core_extensions_registration(cmark_plugin *plugin) { return 1; } diff --git a/extensions/core-extensions.h b/extensions/core-extensions.h new file mode 100644 index 00000000..59d8056d --- /dev/null +++ b/extensions/core-extensions.h @@ -0,0 +1,16 @@ +#ifndef CORE_EXTENSIONS_H +#define CORE_EXTENSIONS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int core_extensions_registration(cmark_plugin *plugin); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extensions/ext_scanners.c b/extensions/ext_scanners.c deleted file mode 100644 index 78df8d24..00000000 --- a/extensions/ext_scanners.c +++ /dev/null @@ -1,585 +0,0 @@ -/* Generated by re2c 0.16 */ -#include -#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; - } -} diff --git a/extensions/ext_scanners.h b/extensions/ext_scanners.h deleted file mode 100644 index c96b1849..00000000 --- a/extensions/ext_scanners.h +++ /dev/null @@ -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 diff --git a/extensions/ext_scanners.re b/extensions/ext_scanners.re deleted file mode 100644 index 7ad561f5..00000000 --- a/extensions/ext_scanners.re +++ /dev/null @@ -1,65 +0,0 @@ -#include -#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; } -*/ -} diff --git a/man/man3/cmark.3 b/man/man3/cmark.3 index f32644a0..692588d7 100644 --- a/man/man3/cmark.3 +++ b/man/man3/cmark.3 @@ -27,37 +27,31 @@ Node Structure .RS 0n typedef enum { /* Error status */ - CMARK_NODE_NONE, + CMARK_NODE_NONE = 0x0000, /* Block */ - CMARK_NODE_DOCUMENT, - CMARK_NODE_BLOCK_QUOTE, - CMARK_NODE_LIST, - CMARK_NODE_ITEM, - CMARK_NODE_CODE_BLOCK, - CMARK_NODE_HTML_BLOCK, - CMARK_NODE_CUSTOM_BLOCK, - CMARK_NODE_PARAGRAPH, - CMARK_NODE_HEADING, - CMARK_NODE_THEMATIC_BREAK, - - CMARK_NODE_FIRST_BLOCK = CMARK_NODE_DOCUMENT, - CMARK_NODE_LAST_BLOCK = CMARK_NODE_THEMATIC_BREAK, + CMARK_NODE_DOCUMENT = CMARK_NODE_TYPE_BLOCK | 0x0001, + CMARK_NODE_BLOCK_QUOTE = CMARK_NODE_TYPE_BLOCK | 0x0002, + CMARK_NODE_LIST = CMARK_NODE_TYPE_BLOCK | 0x0003, + CMARK_NODE_ITEM = CMARK_NODE_TYPE_BLOCK | 0x0004, + CMARK_NODE_CODE_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0005, + CMARK_NODE_HTML_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0006, + CMARK_NODE_CUSTOM_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0007, + CMARK_NODE_PARAGRAPH = CMARK_NODE_TYPE_BLOCK | 0x0008, + CMARK_NODE_HEADING = CMARK_NODE_TYPE_BLOCK | 0x0009, + CMARK_NODE_THEMATIC_BREAK = CMARK_NODE_TYPE_BLOCK | 0x000a, /* Inline */ - CMARK_NODE_TEXT, - CMARK_NODE_SOFTBREAK, - CMARK_NODE_LINEBREAK, - CMARK_NODE_CODE, - CMARK_NODE_HTML_INLINE, - CMARK_NODE_CUSTOM_INLINE, - CMARK_NODE_EMPH, - CMARK_NODE_STRONG, - CMARK_NODE_LINK, - CMARK_NODE_IMAGE, - - CMARK_NODE_FIRST_INLINE = CMARK_NODE_TEXT, - CMARK_NODE_LAST_INLINE = CMARK_NODE_IMAGE, + CMARK_NODE_TEXT = CMARK_NODE_TYPE_INLINE | 0x0001, + CMARK_NODE_SOFTBREAK = CMARK_NODE_TYPE_INLINE | 0x0002, + CMARK_NODE_LINEBREAK = CMARK_NODE_TYPE_INLINE | 0x0003, + CMARK_NODE_CODE = CMARK_NODE_TYPE_INLINE | 0x0004, + CMARK_NODE_HTML_INLINE = CMARK_NODE_TYPE_INLINE | 0x0005, + CMARK_NODE_CUSTOM_INLINE = CMARK_NODE_TYPE_INLINE | 0x0006, + CMARK_NODE_EMPH = CMARK_NODE_TYPE_INLINE | 0x0007, + CMARK_NODE_STRONG = CMARK_NODE_TYPE_INLINE | 0x0008, + CMARK_NODE_LINK = CMARK_NODE_TYPE_INLINE | 0x0009, + CMARK_NODE_IMAGE = CMARK_NODE_TYPE_INLINE | 0x000a, } cmark_node_type; .RE \f[] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c5d1c0ef..6f753955 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,7 +54,6 @@ set(LIBRARY_SOURCES set(PROGRAM "cmark") set(PROGRAM_SOURCES - ${LIBRARY_SOURCES} main.c ) @@ -68,6 +67,11 @@ include (GenerateExportHeader) add_executable(${PROGRAM} ${PROGRAM_SOURCES}) 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: set_target_properties(${PROGRAM} PROPERTIES COMPILE_FLAGS -DCMARK_STATIC_DEFINE) @@ -197,7 +201,7 @@ if(MSVC) 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 -std=c99 -pedantic") + 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 diff --git a/src/blocks.c b/src/blocks.c index 9f93c06f..1efda3d7 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -82,11 +82,11 @@ static cmark_node *make_document(cmark_mem *mem) { } int cmark_parser_attach_syntax_extension(cmark_parser *parser, - cmark_syntax_extension *extension) { - parser->syntax_extensions = cmark_llist_append(parser->syntax_extensions, extension); - if (extension->match_inline && extension->insert_inline_from_delim) { + cmark_syntax_extension *extension) { + parser->syntax_extensions = cmark_llist_append(parser->mem, parser->syntax_extensions, extension); + if (extension->match_inline || extension->insert_inline_from_delim) { parser->inline_syntax_extensions = cmark_llist_append( - parser->inline_syntax_extensions, extension); + parser->mem, parser->inline_syntax_extensions, extension); } return 1; @@ -145,8 +145,8 @@ void cmark_parser_free(cmark_parser *parser) { cmark_parser_dispose(parser); cmark_strbuf_free(&parser->curline); cmark_strbuf_free(&parser->linebuf); - cmark_llist_free(parser->syntax_extensions); - cmark_llist_free(parser->inline_syntax_extensions); + cmark_llist_free(parser->mem, parser->syntax_extensions); + cmark_llist_free(parser->mem, parser->inline_syntax_extensions); mem->free(parser); } @@ -173,31 +173,19 @@ static bool is_blank(cmark_strbuf *s, bufsize_t offset) { 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) { return (block_type == CMARK_NODE_PARAGRAPH || block_type == CMARK_NODE_HEADING || block_type == CMARK_NODE_CODE_BLOCK); } -static CMARK_INLINE bool contains_inlines(cmark_node_type block_type) { - return (block_type == CMARK_NODE_PARAGRAPH || - block_type == CMARK_NODE_HEADING || - block_type == CMARK_NODE_TABLE_CELL); +static CMARK_INLINE bool contains_inlines(cmark_node *node) { + if (node->extension && node->extension->contains_inlines_func) { + return node->extension->contains_inlines_func(node->extension, node); + } + + return (node->type == CMARK_NODE_PARAGRAPH || + node->type == CMARK_NODE_HEADING); } 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, // 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); } @@ -397,7 +385,7 @@ static cmark_node *add_child(cmark_parser *parser, cmark_node *parent, 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; 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_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) { cur = cmark_iter_get_node(iter); if (ev_type == CMARK_EVENT_ENTER) { - if (contains_inlines(cur->type)) { + if (contains_inlines(cur)) { cmark_parse_inlines(parser, cur, refmap, options); } } } - manage_extensions_special_characters(parser, false); + cmark_manage_extensions_special_characters(parser, false); 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 */ 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: parser->last_line_length = input.len; @@ -1305,6 +1293,7 @@ finished: cmark_node *cmark_parser_finish(cmark_parser *parser) { cmark_node *res; + cmark_llist *extensions; /* Parser was already finished once */ if (parser->root == NULL) @@ -1333,6 +1322,15 @@ cmark_node *cmark_parser_finish(cmark_parser *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; } diff --git a/src/buffer.h b/src/buffer.h index e8780753..90fa7df7 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -32,22 +32,32 @@ extern unsigned char cmark_strbuf__initbuf[]; * For the cases where CMARK_BUF_INIT cannot be used to do static * initialization. */ +CMARK_EXPORT void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf, bufsize_t initial_size); /** * Grow the buffer to hold at least `target_size` bytes. */ +CMARK_EXPORT void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size); +CMARK_EXPORT void cmark_strbuf_free(cmark_strbuf *buf); + +CMARK_EXPORT void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b); +CMARK_EXPORT bufsize_t cmark_strbuf_len(const cmark_strbuf *buf); +CMARK_EXPORT int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b); +CMARK_EXPORT unsigned char *cmark_strbuf_detach(cmark_strbuf *buf); + +CMARK_EXPORT void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize, 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]) +CMARK_EXPORT void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data, bufsize_t len); + +CMARK_EXPORT void cmark_strbuf_sets(cmark_strbuf *buf, const char *string); + +CMARK_EXPORT void cmark_strbuf_putc(cmark_strbuf *buf, int c); + +CMARK_EXPORT void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data, bufsize_t len); + +CMARK_EXPORT void cmark_strbuf_puts(cmark_strbuf *buf, const char *string); + +CMARK_EXPORT void cmark_strbuf_clear(cmark_strbuf *buf); +CMARK_EXPORT 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); + +CMARK_EXPORT void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n); + +CMARK_EXPORT void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len); + +CMARK_EXPORT void cmark_strbuf_rtrim(cmark_strbuf *buf); + +CMARK_EXPORT void cmark_strbuf_trim(cmark_strbuf *buf); + +CMARK_EXPORT void cmark_strbuf_normalize_whitespace(cmark_strbuf *s); + +CMARK_EXPORT void cmark_strbuf_unescape(cmark_strbuf *s); #ifdef __cplusplus diff --git a/src/cmark.c b/src/cmark.c index c9d450fd..5758da90 100644 --- a/src/cmark.c +++ b/src/cmark.c @@ -7,6 +7,9 @@ #include "cmark.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; } 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); - result = cmark_render_html(doc, options); + result = cmark_render_html(doc, options, NULL); cmark_node_free(doc); return result; } - -int cmark_init(void) { - cmark_discover_plugins(); - return 1; -} - -int cmark_deinit(void) { - cmark_release_plugins(); - return 1; -} diff --git a/src/cmark.h b/src/cmark.h index fbede273..cc1b089c 100644 --- a/src/cmark.h +++ b/src/cmark.h @@ -1,9 +1,9 @@ -#ifndef CMARK_H -#define CMARK_H +#ifndef CMARK_CMARK_H +#define CMARK_CMARK_H #include -#include -#include +#include "cmark_export.h" +#include "cmark_version.h" #ifdef __cplusplus extern "C" { @@ -30,49 +30,44 @@ char *cmark_markdown_to_html(const char *text, size_t len, int options); /** ## 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 { /* Error status */ - CMARK_NODE_NONE, + CMARK_NODE_NONE = 0x0000, /* Block */ - CMARK_NODE_DOCUMENT, - CMARK_NODE_BLOCK_QUOTE, - CMARK_NODE_LIST, - CMARK_NODE_ITEM, - CMARK_NODE_CODE_BLOCK, - CMARK_NODE_HTML_BLOCK, - CMARK_NODE_CUSTOM_BLOCK, - CMARK_NODE_PARAGRAPH, - CMARK_NODE_HEADING, - CMARK_NODE_THEMATIC_BREAK, - - /* 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, + CMARK_NODE_DOCUMENT = CMARK_NODE_TYPE_BLOCK | 0x0001, + CMARK_NODE_BLOCK_QUOTE = CMARK_NODE_TYPE_BLOCK | 0x0002, + CMARK_NODE_LIST = CMARK_NODE_TYPE_BLOCK | 0x0003, + CMARK_NODE_ITEM = CMARK_NODE_TYPE_BLOCK | 0x0004, + CMARK_NODE_CODE_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0005, + CMARK_NODE_HTML_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0006, + CMARK_NODE_CUSTOM_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0007, + CMARK_NODE_PARAGRAPH = CMARK_NODE_TYPE_BLOCK | 0x0008, + CMARK_NODE_HEADING = CMARK_NODE_TYPE_BLOCK | 0x0009, + CMARK_NODE_THEMATIC_BREAK = CMARK_NODE_TYPE_BLOCK | 0x000a, /* Inline */ - CMARK_NODE_TEXT, - CMARK_NODE_SOFTBREAK, - CMARK_NODE_LINEBREAK, - CMARK_NODE_CODE, - CMARK_NODE_HTML_INLINE, - CMARK_NODE_CUSTOM_INLINE, - CMARK_NODE_EMPH, - CMARK_NODE_STRONG, - CMARK_NODE_LINK, - CMARK_NODE_IMAGE, - - /* 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_TEXT = CMARK_NODE_TYPE_INLINE | 0x0001, + CMARK_NODE_SOFTBREAK = CMARK_NODE_TYPE_INLINE | 0x0002, + CMARK_NODE_LINEBREAK = CMARK_NODE_TYPE_INLINE | 0x0003, + CMARK_NODE_CODE = CMARK_NODE_TYPE_INLINE | 0x0004, + CMARK_NODE_HTML_INLINE = CMARK_NODE_TYPE_INLINE | 0x0005, + CMARK_NODE_CUSTOM_INLINE = CMARK_NODE_TYPE_INLINE | 0x0006, + CMARK_NODE_EMPH = CMARK_NODE_TYPE_INLINE | 0x0007, + CMARK_NODE_STRONG = CMARK_NODE_TYPE_INLINE | 0x0008, + CMARK_NODE_LINK = CMARK_NODE_TYPE_INLINE | 0x0009, + CMARK_NODE_IMAGE = CMARK_NODE_TYPE_INLINE | 0x000a, } cmark_node_type; +extern cmark_node_type CMARK_NODE_LAST_BLOCK; +extern cmark_node_type CMARK_NODE_LAST_INLINE; + /* For backwards compatibility: */ #define CMARK_NODE_HEADER CMARK_NODE_HEADING #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_iter cmark_iter; -typedef void (*cmark_free_func) (void *user_data); - /** * ## Custom memory allocator support */ @@ -128,6 +121,10 @@ cmark_mem *cmark_get_arena_mem_allocator(); CMARK_EXPORT 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 @@ -152,21 +149,23 @@ typedef struct _cmark_llist * head of the list. */ CMARK_EXPORT -cmark_llist * cmark_llist_append (cmark_llist * head, +cmark_llist * cmark_llist_append (cmark_mem * mem, + cmark_llist * head, void * data); /** Free the list starting with 'head', calling 'free_func' with the * data pointer of each of its elements */ 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); /** Free the list starting with 'head' */ CMARK_EXPORT -void cmark_llist_free (cmark_llist * head); - +void cmark_llist_free (cmark_mem * mem, + cmark_llist * head); /** * ## 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_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 */ @@ -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); +/** Ensures a node and all its children own their own chunk memory. + */ +CMARK_EXPORT void cmark_node_own(cmark_node *root); + /** * ## 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. */ 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 * the resulting string. */ 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. * It is the caller's responsibility to free the returned buffer. diff --git a/src/cmark_ctype.h b/src/cmark_ctype.h index 9a076185..4b90940a 100644 --- a/src/cmark_ctype.h +++ b/src/cmark_ctype.h @@ -5,18 +5,25 @@ extern "C" { #endif +#include "cmark_export.h" + /** Locale-independent versions of functions from ctype.h. * We want cmark to behave the same no matter what the system locale. */ +CMARK_EXPORT int cmark_isspace(char c); +CMARK_EXPORT int cmark_ispunct(char c); +CMARK_EXPORT int cmark_isalnum(char c); +CMARK_EXPORT int cmark_isdigit(char c); +CMARK_EXPORT int cmark_isalpha(char c); #ifdef __cplusplus diff --git a/src/cmark_extension_api.h b/src/cmark_extension_api.h index bae8310d..e62e106f 100644 --- a/src/cmark_extension_api.h +++ b/src/cmark_extension_api.h @@ -1,12 +1,13 @@ -#ifndef CMARK_EXTENSION_API_H -#define CMARK_EXTENSION_API_H +#ifndef CMARK_CMARK_EXTENSION_API_H +#define CMARK_CMARK_EXTENSION_API_H #ifdef __cplusplus extern "C" { #endif #include -#include "buffer.h" +#include +#include /** * ## Extension Support @@ -217,16 +218,48 @@ typedef int (*cmark_match_block_func) (cmark_syntax_extension *extension, int len, 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. */ 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'. */ CMARK_EXPORT 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' */ CMARK_EXPORT @@ -257,6 +290,54 @@ CMARK_EXPORT void cmark_syntax_extension_set_special_inline_chars(cmark_syntax_extension *extension, 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' */ CMARK_EXPORT @@ -264,6 +345,12 @@ void cmark_syntax_extension_set_private(cmark_syntax_extension *extension, void *priv, 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. */ CMARK_EXPORT @@ -477,6 +564,30 @@ void cmark_inline_parser_advance_offset(cmark_inline_parser *parser); CMARK_EXPORT 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 */ CMARK_EXPORT @@ -539,6 +650,10 @@ int cmark_inline_parser_scan_delimiters(cmark_inline_parser *parser, int *right_flanking, int *punct_before, int *punct_after); + +CMARK_EXPORT +void cmark_manage_extensions_special_characters(cmark_parser *parser, bool add); + #ifdef __cplusplus } #endif diff --git a/src/commonmark.c b/src/commonmark.c index e41e4ee3..eeaf3339 100644 --- a/src/commonmark.c +++ b/src/commonmark.c @@ -11,6 +11,7 @@ #include "utf8.h" #include "scanners.h" #include "render.h" +#include "syntax_extension.h" #define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping) #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. static cmark_node *get_containing_block(cmark_node *node) { while (node) { - if (node->type >= CMARK_NODE_FIRST_BLOCK && - node->type <= CMARK_NODE_LAST_BLOCK) { + if (CMARK_NODE_BLOCK_P(node)) { return node; } else { 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))); } + 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) { case CMARK_NODE_DOCUMENT: break; @@ -335,33 +340,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node, } 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: OUT(cmark_node_get_literal(node), allow_wrap, NORMAL); break; @@ -484,10 +462,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node, } break; - case CMARK_NODE_STRIKETHROUGH: - OUT(cmark_node_get_string_content(node), false, LITERAL); - break; - default: assert(false); break; diff --git a/src/config.h.in b/src/config.h.in index e14bf73f..de1a4dd4 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -69,8 +69,6 @@ CMARK_INLINE int c99_snprintf(char *outBuf, size_t size, const char *format, ... #endif -#define EXTENSION_DIR LIBDIR "/extensions" - #ifdef __cplusplus } #endif diff --git a/src/houdini.h b/src/houdini.h index f738e824..7852c3a8 100644 --- a/src/houdini.h +++ b/src/houdini.h @@ -31,17 +31,23 @@ extern "C" { #define HOUDINI_ESCAPED_SIZE(x) (((x)*12) / 10) #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); -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); -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); -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); -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); -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); #ifdef __cplusplus diff --git a/src/houdini_html_e.c b/src/houdini_html_e.c index 0e539f03..da0b15c5 100644 --- a/src/houdini_html_e.c +++ b/src/houdini_html_e.c @@ -48,7 +48,7 @@ int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src, bufsize_t size, if (unlikely(i >= size)) 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) { cmark_strbuf_putc(ob, src[i]); } else { diff --git a/src/html.c b/src/html.c index 600d9832..f6525f73 100644 --- a/src/html.c +++ b/src/html.c @@ -5,12 +5,10 @@ #include "cmark_ctype.h" #include "config.h" #include "cmark.h" -#include "node.h" -#include "buffer.h" #include "houdini.h" #include "scanners.h" - -#define BUFFER_SIZE 100 +#include "syntax_extension.h" +#include "html.h" // 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); } -static CMARK_INLINE void cr(cmark_strbuf *html) { - if (html->size && html->ptr[html->size - 1] != '\n') - cmark_strbuf_putc(html, '\n'); -} +static void filter_html_block(cmark_html_renderer *renderer, uint8_t *data, size_t len) { + cmark_strbuf *html = renderer->html; + cmark_llist *it; + cmark_syntax_extension *ext; + bool filtered; + uint8_t *match; -struct render_state { - cmark_strbuf *html; - cmark_node *plain; - bool need_closing_table_body; - bool in_table_header; -}; + while (len) { + match = (uint8_t *) memchr(data, '<', len); + if (!match) + break; -static void S_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); + if (match != data) { + cmark_strbuf_put(html, data, match - data); + len -= (match - data); + data = match; + } + + filtered = false; + for (it = renderer->filter_extensions; it; it = it->next) { + ext = ((cmark_syntax_extension *) it->data); + if (!ext->html_filter_func(ext, data, len)) { + filtered = true; + break; + } + } + + if (!filtered) { + cmark_strbuf_putc(html, '<'); + } else { + cmark_strbuf_puts(html, "<"); + } + + ++data; + --len; } + + if (len) + cmark_strbuf_put(html, data, len); } -static int S_render_node(cmark_node *node, cmark_event_type ev_type, - struct render_state *state, int options) { +static int S_render_node(cmark_html_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { cmark_node *parent; cmark_node *grandparent; - cmark_strbuf *html = state->html; + cmark_strbuf *html = renderer->html; + cmark_llist *it; + cmark_syntax_extension *ext; char start_heading[] = "plain == node) { // back at original node - state->plain = NULL; + if (renderer->plain == node) { // back at original node + renderer->plain = NULL; } - if (state->plain != NULL) { + if (renderer->plain != NULL) { switch (node->type) { case CMARK_NODE_TEXT: case CMARK_NODE_CODE: @@ -77,18 +96,23 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, 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) { case CMARK_NODE_DOCUMENT: break; case CMARK_NODE_BLOCK_QUOTE: if (entering) { - cr(html); + cmark_html_render_cr(html); cmark_strbuf_puts(html, "\n"); } else { - cr(html); + cmark_html_render_cr(html); cmark_strbuf_puts(html, "\n"); } break; @@ -98,19 +122,19 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, int start = node->as.list.start; if (entering) { - cr(html); + cmark_html_render_cr(html); if (list_type == CMARK_BULLET_LIST) { cmark_strbuf_puts(html, "\n"); } else if (start == 1) { cmark_strbuf_puts(html, "\n"); } else { snprintf(buffer, BUFFER_SIZE, "
      \n"); } } else { @@ -122,9 +146,9 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, case CMARK_NODE_ITEM: if (entering) { - cr(html); + cmark_html_render_cr(html); cmark_strbuf_puts(html, "'); } else { cmark_strbuf_puts(html, "\n"); @@ -133,10 +157,10 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, case CMARK_NODE_HEADING: if (entering) { - cr(html); + cmark_html_render_cr(html); start_heading[2] = (char)('0' + node->as.heading.level); cmark_strbuf_puts(html, start_heading); - S_render_sourcepos(node, html, options); + cmark_html_render_sourcepos(node, html, options); cmark_strbuf_putc(html, '>'); } else { 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; case CMARK_NODE_CODE_BLOCK: - cr(html); + cmark_html_render_cr(html); if (node->as.code.info.len == 0) { cmark_strbuf_puts(html, ""); } else { 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, "as.code.info.data, first_tag); cmark_strbuf_puts(html, "\">"); @@ -171,17 +195,19 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, break; case CMARK_NODE_HTML_BLOCK: - cr(html); + cmark_html_render_cr(html); if (options & CMARK_OPT_SAFE) { cmark_strbuf_puts(html, ""); + } else if (renderer->filter_extensions) { + filter_html_block(renderer, node->as.literal.data, node->as.literal.len); } else { cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); } - cr(html); + cmark_html_render_cr(html); break; case CMARK_NODE_CUSTOM_BLOCK: - cr(html); + cmark_html_render_cr(html); if (entering) { cmark_strbuf_put(html, node->as.custom.on_enter.data, 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, node->as.custom.on_exit.len); } - cr(html); + cmark_html_render_cr(html); break; case CMARK_NODE_THEMATIC_BREAK: - cr(html); + cmark_html_render_cr(html); cmark_strbuf_puts(html, "\n"); break; @@ -209,9 +235,9 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, } if (!tight) { if (entering) { - cr(html); + cmark_html_render_cr(html); cmark_strbuf_puts(html, "'); } else { cmark_strbuf_puts(html, "

      \n"); @@ -219,65 +245,6 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, } break; - case CMARK_NODE_TABLE: - if (entering) { - cr(html); - cmark_strbuf_puts(html, "'); - state->need_closing_table_body = false; - } else { - if (state->need_closing_table_body) - cmark_strbuf_puts(html, ""); - state->need_closing_table_body = false; - cmark_strbuf_puts(html, ""); - } - 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, ""); - cr(html); - } - cmark_strbuf_puts(html, "'); - } else { - cr(html); - cmark_strbuf_puts(html, ""); - if (node->as.table_row.is_header) { - cr(html); - cmark_strbuf_puts(html, ""); - cr(html); - cmark_strbuf_puts(html, ""); - 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, "'); - } else { - if (state->in_table_header) { - cmark_strbuf_puts(html, ""); - } else { - cmark_strbuf_puts(html, ""); - } - } - break; - case CMARK_NODE_TEXT: escape_html(html, node->as.literal.data, node->as.literal.len); break; @@ -306,7 +273,20 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, if (options & CMARK_OPT_SAFE) { cmark_strbuf_puts(html, ""); } else { - cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); + filtered = false; + for (it = renderer->filter_extensions; it; it = it->next) { + ext = (cmark_syntax_extension *) it->data; + if (!ext->html_filter_func(ext, node->as.literal.data, node->as.literal.len)) { + filtered = true; + break; + } + } + if (!filtered) { + cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); + } else { + cmark_strbuf_puts(html, "<"); + cmark_strbuf_put(html, node->as.literal.data + 1, node->as.literal.len - 1); + } } break; @@ -363,7 +343,7 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, node->as.link.url.len); } cmark_strbuf_puts(html, "\" alt=\""); - state->plain = node; + renderer->plain = node; } else { if (node->as.link.title.len) { cmark_strbuf_puts(html, "\" title=\""); @@ -374,41 +354,41 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type, } break; - case CMARK_NODE_STRIKETHROUGH: - if (entering) { - cmark_strbuf_puts(html, ""); - } else { - cmark_strbuf_puts(html, ""); - } - break; - default: assert(false); break; } - // cmark_strbuf_putc(html, 'x'); return 1; } -char *cmark_render_html(cmark_node *root, int options) { - return cmark_render_html_with_mem(root, options, cmark_node_mem(root)); +char *cmark_render_html(cmark_node *root, int options, cmark_llist *extensions) { + 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; cmark_strbuf html = CMARK_BUF_INIT(mem); cmark_event_type ev_type; 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); + 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) { 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); + cmark_llist_free(mem, renderer.filter_extensions); + cmark_iter_free(iter); return result; } diff --git a/src/html.h b/src/html.h new file mode 100644 index 00000000..aeba7bcd --- /dev/null +++ b/src/html.h @@ -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 diff --git a/src/inlines.c b/src/inlines.c index dec4860b..da6a7ef9 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -1105,7 +1105,6 @@ static cmark_node *try_extensions(cmark_parser *parser, for (tmp = parser->inline_syntax_extensions; tmp; tmp = tmp->next) { cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data; - res = ext->match_inline(ext, parser, parent, c, subj); 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. -extern void cmark_parse_inlines(cmark_parser *parser, - cmark_node *parent, - cmark_reference_map *refmap, - int options) { +void cmark_parse_inlines(cmark_parser *parser, + cmark_node *parent, + cmark_reference_map *refmap, + int options) { subject subj; subject_from_buf(parser->mem, &subj, &parent->content, refmap); cmark_chunk_rtrim(&subj.input); @@ -1409,6 +1408,35 @@ int cmark_inline_parser_get_offset(cmark_inline_parser *parser) { 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) { return parser->last_delim; } diff --git a/src/inlines.h b/src/inlines.h index 586b53fa..0d8305c2 100644 --- a/src/inlines.h +++ b/src/inlines.h @@ -5,9 +5,12 @@ extern "C" { #endif +#include "references.h" + cmark_chunk cmark_clean_url(cmark_mem *mem, cmark_chunk *url); cmark_chunk cmark_clean_title(cmark_mem *mem, cmark_chunk *title); +CMARK_EXPORT void cmark_parse_inlines(cmark_parser *parser, cmark_node *parent, cmark_reference_map *refmap, diff --git a/src/iterator.c b/src/iterator.c index 24423a21..149a445e 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -6,12 +6,6 @@ #include "cmark.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) { if (root == 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); } 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) { @@ -118,3 +123,36 @@ void cmark_consolidate_text_nodes(cmark_node *root) { cmark_strbuf_free(&buf); 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); +} diff --git a/src/latex.c b/src/latex.c index a8d485c6..068dc3f6 100644 --- a/src/latex.c +++ b/src/latex.c @@ -10,6 +10,7 @@ #include "utf8.h" #include "scanners.h" #include "render.h" +#include "syntax_extension.h" #define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping) #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; bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options); - // avoid warning about unused parameter: - (void)(options); + if (node->extension && node->extension->latex_render_func) { + node->extension->latex_render_func(node->extension, renderer, node, ev_type, options); + return 1; + } switch (node->type) { case CMARK_NODE_DOCUMENT: @@ -346,44 +349,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node, } 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: OUT(cmark_node_get_literal(node), allow_wrap, NORMAL); break; @@ -478,15 +443,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node, } break; - case CMARK_NODE_STRIKETHROUGH: - /* requires \usepackage{ulem} */ - if (entering) { - LIT("\\sout{"); - } else { - LIT("}"); - } - break; - default: assert(false); break; diff --git a/src/libcmark.pc.in b/src/libcmark.pc.in index c3153ba2..024ae483 100644 --- a/src/libcmark.pc.in +++ b/src/libcmark.pc.in @@ -6,5 +6,5 @@ includedir=@CMAKE_INSTALL_PREFIX@/include Name: libcmark Description: CommonMark parsing, rendering, and manipulation Version: @PROJECT_VERSION@ -Libs: -L${libdir} -lcmark -ldl +Libs: -L${libdir} -lcmark Cflags: -I${includedir} diff --git a/src/linked_list.c b/src/linked_list.c index 7d6690da..f8bc6042 100644 --- a/src/linked_list.c +++ b/src/linked_list.c @@ -2,9 +2,9 @@ #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 *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->next = NULL; @@ -19,19 +19,19 @@ cmark_llist *cmark_llist_append(cmark_llist *head, void *data) { 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; for (tmp = head; tmp;) { if (free_func) - free_func(tmp->data); + free_func(mem, tmp->data); prev = tmp; tmp = tmp->next; - free(prev); + mem->free(prev); } } -void cmark_llist_free(cmark_llist *head) { - cmark_llist_free_full(head, NULL); +void cmark_llist_free(cmark_mem *mem, cmark_llist *head) { + cmark_llist_free_full(mem, head, NULL); } diff --git a/src/main.c b/src/main.c index a1cca572..6fe54d10 100644 --- a/src/main.c +++ b/src/main.c @@ -8,8 +8,11 @@ #include "node.h" #include "cmark_extension_api.h" #include "syntax_extension.h" +#include "parser.h" #include "registry.h" +#include "../extensions/core-extensions.h" + #if defined(_WIN32) && !defined(__CYGWIN__) #include #include @@ -42,14 +45,14 @@ void print_usage() { } static bool print_document(cmark_node *document, writer_format writer, - int options, int width) { + int options, int width, cmark_parser *parser) { char *result; cmark_mem *mem = cmark_get_default_mem_allocator(); switch (writer) { 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; case FORMAT_XML: 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; } printf("%s", result); - cmark_node_mem(document)->free(result); + mem->free(result); return true; } @@ -79,13 +82,14 @@ static void print_extensions(void) { 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) { cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data; printf("%s\n", ext->name); } - cmark_llist_free(syntax_extensions); + cmark_llist_free(mem, syntax_extensions); } int main(int argc, char *argv[]) { @@ -101,6 +105,8 @@ int main(int argc, char *argv[]) { int options = CMARK_OPT_DEFAULT; int res = 1; + cmark_register_plugin(core_extensions_registration); + #if defined(_WIN32) && !defined(__CYGWIN__) _setmode(_fileno(stdin), _O_BINARY); _setmode(_fileno(stdout), _O_BINARY); @@ -229,10 +235,9 @@ int main(int argc, char *argv[]) { document = cmark_parser_finish(parser); - if (!print_document(document, writer, options, width)) + if (!print_document(document, writer, options, width, parser)) goto failure; - success: res = 0; @@ -247,6 +252,8 @@ failure: cmark_arena_reset(); #endif + cmark_release_plugins(); + free(files); return res; diff --git a/src/man.c b/src/man.c index 205a07cb..1ae1ac89 100644 --- a/src/man.c +++ b/src/man.c @@ -9,6 +9,7 @@ #include "buffer.h" #include "utf8.h" #include "render.h" +#include "syntax_extension.h" #define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping) #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 allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options); - // avoid unused parameter error: - (void)(options); + if (node->extension && node->extension->man_render_func) { + node->extension->man_render_func(node->extension, renderer, node, ev_type, options); + return 1; + } switch (node->type) { case CMARK_NODE_DOCUMENT: @@ -186,40 +189,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node, } 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: OUT(cmark_node_get_literal(node), allow_wrap, NORMAL); break; @@ -286,16 +255,6 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node, } break; - case CMARK_NODE_STRIKETHROUGH: - if (entering) { - CR(); - LIT(".ST \""); - } else { - LIT("\""); - CR(); - } - break; - default: assert(false); break; diff --git a/src/node.c b/src/node.c index 2fd674f3..266cf250 100644 --- a/src/node.c +++ b/src/node.c @@ -3,25 +3,47 @@ #include "config.h" #include "node.h" +#include "syntax_extension.h" static void S_node_unlink(cmark_node *node); #define NODE_MEM(node) cmark_node_mem(node) -static CMARK_INLINE bool S_is_block(cmark_node *node) { - if (node == NULL) { - return false; - } - return node->type >= CMARK_NODE_FIRST_BLOCK && - node->type <= CMARK_NODE_LAST_BLOCK; -} +bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) { + if (child_type == CMARK_NODE_DOCUMENT) { + return false; + } -static CMARK_INLINE bool S_is_inline(cmark_node *node) { - if (node == NULL) { - return false; + if (node->extension && node->extension->can_contain_func) { + return node->extension->can_contain_func(node->extension, node, child_type); } - 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) { @@ -30,6 +52,9 @@ static bool S_can_contain(cmark_node *node, cmark_node *child) { if (node == NULL || child == NULL) { return false; } + if (NODE_MEM(node) != NODE_MEM(child)) { + return 0; + } // Verify that child is not an ancestor of node or equal to node. cur = node; @@ -40,49 +65,7 @@ static bool S_can_contain(cmark_node *node, cmark_node *child) { cur = cur->parent; } while (cur != NULL); - if (child->type == CMARK_NODE_DOCUMENT) { - 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; + return cmark_node_can_contain_type(node, (cmark_node_type) child->type); } 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) { 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.literal); - break; - case CMARK_NODE_TEXT: - case CMARK_NODE_HTML_INLINE: - case CMARK_NODE_CODE: - case CMARK_NODE_HTML_BLOCK: + break; + case CMARK_NODE_TEXT: + case CMARK_NODE_HTML_INLINE: + case CMARK_NODE_CODE: + case CMARK_NODE_HTML_BLOCK: cmark_chunk_free(NODE_MEM(node), &node->as.literal); - break; - case CMARK_NODE_LINK: - case CMARK_NODE_IMAGE: + break; + case CMARK_NODE_LINK: + case CMARK_NODE_IMAGE: cmark_chunk_free(NODE_MEM(node), &node->as.link.url); cmark_chunk_free(NODE_MEM(node), &node->as.link.title); - break; - case CMARK_NODE_CUSTOM_BLOCK: - case CMARK_NODE_CUSTOM_INLINE: + break; + case CMARK_NODE_CUSTOM_BLOCK: + 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_exit); - break; - default: - break; - } + break; + default: + break; + } } // 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); 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); @@ -184,7 +167,7 @@ int cmark_node_set_type(cmark_node * node, cmark_node_type type) { if (type == node->type) return 1; - initial_type = node->type; + initial_type = (cmark_node_type) node->type; node->type = type; if (!S_can_contain(node->parent, node)) { @@ -206,6 +189,10 @@ const char *cmark_node_get_type_string(cmark_node *node) { return "NONE"; } + if (node->extension && node->extension->get_type_string_func) { + return node->extension->get_type_string_func(node->extension, node); + } + switch (node->type) { case CMARK_NODE_NONE: return "none"; @@ -223,15 +210,6 @@ const char *cmark_node_get_type_string(cmark_node *node) { return "html_block"; case CMARK_NODE_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: return "paragraph"; case CMARK_NODE_HEADING: @@ -258,8 +236,6 @@ const char *cmark_node_get_type_string(cmark_node *node) { return "link"; case CMARK_NODE_IMAGE: return "image"; - case CMARK_NODE_STRIKETHROUGH: - return "strikethrough"; } return ""; @@ -760,68 +736,6 @@ int cmark_node_get_end_column(cmark_node *node) { 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. static void S_node_unlink(cmark_node *node) { if (node == NULL) { diff --git a/src/node.h b/src/node.h index cbb0e551..e32814bc 100644 --- a/src/node.h +++ b/src/node.h @@ -47,14 +47,6 @@ typedef struct { cmark_chunk on_exit; } cmark_custom; -typedef struct { - int n_columns; -} cmark_table; - -typedef struct { - bool is_header; -} cmark_table_row; - enum cmark_node__internal_flags { CMARK_NODE__OPEN = (1 << 0), CMARK_NODE__LAST_LINE_BLANK = (1 << 1), @@ -88,9 +80,8 @@ struct cmark_node { cmark_heading heading; cmark_link link; cmark_custom custom; - cmark_table table; - cmark_table_row table_row; int html_block_type; + void *opaque; } 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); +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 } #endif diff --git a/src/parser.h b/src/parser.h index 247423a7..9cdb0717 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,5 +1,5 @@ -#ifndef CMARK_AST_H -#define CMARK_AST_H +#ifndef CMARK_PARSER_H +#define CMARK_PARSER_H #include #include "node.h" diff --git a/src/plugin.c b/src/plugin.c index 39c361ac..3992fe19 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -2,15 +2,17 @@ #include "plugin.h" +extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR; + int cmark_plugin_register_syntax_extension(cmark_plugin * plugin, 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; } cmark_plugin * 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; @@ -19,9 +21,10 @@ cmark_plugin_new(void) { void 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); - free(plugin); + CMARK_DEFAULT_MEM_ALLOCATOR.free(plugin); } cmark_llist * diff --git a/src/registry.c b/src/registry.c index 8f7b9c4e..3ff01f2a 100644 --- a/src/registry.c +++ b/src/registry.c @@ -1,5 +1,3 @@ -#include -#include #include #include #include @@ -10,121 +8,45 @@ #include "registry.h" #include "plugin.h" +extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR; static cmark_llist *syntax_extensions = NULL; -static cmark_llist *plugin_handles = NULL; -static cmark_plugin *scan_file(char* filename) { - char* last_slash = strrchr(filename, '/'); - 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; +void cmark_register_plugin(cmark_plugin_init_func reg_fn) { + cmark_plugin *plugin = cmark_plugin_new(); - if (!last_dot || strcmp(last_dot, ".so")) - goto done; - - 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) + if (!reg_fn(plugin)) { + cmark_plugin_free(plugin); 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) { - cmark_release_plugins(); - scan_path(EXTENSION_DIR); -} + for (it = syntax_extensions_list; it; it = it->next) { + syntax_extensions = cmark_llist_append(&CMARK_DEFAULT_MEM_ALLOCATOR, syntax_extensions, it->data); + } -static void -release_plugin_handle(void *libhandle) { - dlclose(libhandle); + cmark_llist_free(&CMARK_DEFAULT_MEM_ALLOCATOR, syntax_extensions_list); + cmark_plugin_free(plugin); } void cmark_release_plugins(void) { 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); syntax_extensions = NULL; } - - cmark_llist_free_full(plugin_handles, release_plugin_handle); - plugin_handles = NULL; } -cmark_llist *cmark_list_syntax_extensions(void) { - cmark_llist *tmp; +cmark_llist *cmark_list_syntax_extensions(cmark_mem *mem) { + cmark_llist *it; cmark_llist *res = NULL; - for (tmp = syntax_extensions; tmp; tmp = tmp->next) { - res = cmark_llist_append(res, tmp->data); + for (it = syntax_extensions; it; it = it->next) { + res = cmark_llist_append(mem, res, it->data); } return res; } diff --git a/src/registry.h b/src/registry.h index bc566e01..0f0fbae2 100644 --- a/src/registry.h +++ b/src/registry.h @@ -6,10 +6,16 @@ extern "C" { #endif #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); -cmark_llist *cmark_list_syntax_extensions(void); + +CMARK_EXPORT +cmark_llist *cmark_list_syntax_extensions(cmark_mem *mem); #ifdef __cplusplus } diff --git a/src/render.h b/src/render.h index b73ace46..d9d4f4b9 100644 --- a/src/render.h +++ b/src/render.h @@ -32,6 +32,15 @@ struct 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_code_point(cmark_renderer *renderer, uint32_t c); diff --git a/src/scanners.h b/src/scanners.h index 207f91a0..b48ca25e 100644 --- a/src/scanners.h +++ b/src/scanners.h @@ -1,3 +1,6 @@ +#ifndef CMARK_SCANNERS_H +#define CMARK_SCANNERS_H + #include "cmark.h" #include "chunk.h" @@ -53,3 +56,5 @@ bufsize_t _scan_dangerous_url(const unsigned char *p); #ifdef __cplusplus } #endif + +#endif diff --git a/src/syntax_extension.c b/src/syntax_extension.c index d8c4459d..c613f8d1 100644 --- a/src/syntax_extension.c +++ b/src/syntax_extension.c @@ -4,23 +4,38 @@ #include "syntax_extension.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) { - extension->free_function(extension->priv); + extension->free_function(mem, extension->priv); } - cmark_llist_free(extension->special_inline_chars); - free(extension->name); - free(extension); + cmark_llist_free(mem, extension->special_inline_chars); + mem->free(extension->name); + mem->free(extension); } cmark_syntax_extension *cmark_syntax_extension_new(const char *name) { - cmark_syntax_extension *res = (cmark_syntax_extension *) calloc(1, sizeof(cmark_syntax_extension)); - res->name = (char *) malloc(sizeof(char) * (strlen(name)) + 1); + cmark_syntax_extension *res = (cmark_syntax_extension *) _mem->calloc(1, sizeof(cmark_syntax_extension)); + res->name = (char *) _mem->calloc(1, sizeof(char) * (strlen(name)) + 1); strcpy(res->name, name); 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, cmark_open_block_func 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; } +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 *priv, cmark_free_func free_func) { diff --git a/src/syntax_extension.h b/src/syntax_extension.h index f46a7d2f..8b3b407c 100644 --- a/src/syntax_extension.h +++ b/src/syntax_extension.h @@ -1,5 +1,5 @@ -#ifndef SYNTAX_EXTENSION_H -#define SYNTAX_EXTENSION_H +#ifndef CMARK_SYNTAX_EXTENSION_H +#define CMARK_SYNTAX_EXTENSION_H #include "cmark.h" #include "cmark_extension_api.h" @@ -13,6 +13,15 @@ struct cmark_syntax_extension { char * name; void * priv; 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 diff --git a/test/entity_tests.py b/test/entity_tests.py index 0e3daad0..3abb3b8c 100644 --- a/test/entity_tests.py +++ b/test/entity_tests.py @@ -54,7 +54,6 @@ for entity, utf8 in entities: print(entity, '[ERRORED (return code {})]'.format(rc)) print(err) elif check in actual: - print(entity, '[PASSED]') passed += 1 else: print(entity, '[FAILED]') diff --git a/toolchain-mingw32.cmake b/toolchain-mingw32.cmake index 61c62a83..c1c6971d 100644 --- a/toolchain-mingw32.cmake +++ b/toolchain-mingw32.cmake @@ -9,7 +9,7 @@ SET(CMAKE_RC_COMPILER i586-mingw32msvc-windres) # here is the target environment located 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 # programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)