From 3d4cf4ceb10b0e822e9856da3372e49b86a7dad8 Mon Sep 17 00:00:00 2001 From: debuggio Date: Wed, 8 Mar 2017 17:05:19 -0800 Subject: [PATCH 1/6] Added nolinks flag to skip links during rendering --- fuzzing/snudown-validator.c | 15 +++++++++ snudown.c | 16 ++++++++++ test_snudown.py | 64 +++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/fuzzing/snudown-validator.c b/fuzzing/snudown-validator.c index 153e1c4..f2c06d8 100644 --- a/fuzzing/snudown-validator.c +++ b/fuzzing/snudown-validator.c @@ -22,6 +22,7 @@ enum snudown_renderer_mode { RENDERER_USERTEXT = 0, RENDERER_WIKI, + RENDERER_USERTEXT_WITHOUTLINKS, RENDERER_COUNT }; @@ -60,6 +61,12 @@ static const unsigned int snudown_default_md_flags = MKDEXT_STRIKETHROUGH | MKDEXT_TABLES; +static const unsigned int snudown_default_md_flags_without_links = + MKDEXT_NO_INTRA_EMPHASIS | + MKDEXT_SUPERSCRIPT | + MKDEXT_STRIKETHROUGH | + MKDEXT_TABLES; + static const unsigned int snudown_default_render_flags = HTML_SKIP_HTML | HTML_SKIP_IMAGES | @@ -129,6 +136,13 @@ void init_wiki_renderer() { sundown[RENDERER_WIKI].toc_state = &wiki_toc_state; } +void init_default_renderer_without_links() { + sundown[RENDERER_USERTEXT_WITHOUTLINKS].main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 0); + sundown[RENDERER_USERTEXT_WITHOUTLINKS].toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 1); + sundown[RENDERER_USERTEXT_WITHOUTLINKS].state = &usertext_state; + sundown[RENDERER_USERTEXT_WITHOUTLINKS].toc_state = &usertext_toc_state; +} + void snudown_md(struct buf *ob, const uint8_t *document, size_t doc_size, int wiki_mode) { @@ -172,6 +186,7 @@ main(int argc, char **argv) { init_default_renderer(); init_wiki_renderer(); + init_default_renderer_without_links(); struct buf *ib, *ob; int size_read = 0, wiki_mode = 0, i = 0, have_errors = 0; diff --git a/snudown.c b/snudown.c index e268f66..be4ae27 100644 --- a/snudown.c +++ b/snudown.c @@ -10,6 +10,7 @@ enum snudown_renderer_mode { RENDERER_USERTEXT = 0, RENDERER_WIKI, + RENDERER_USERTEXT_WITHOUTLINKS, RENDERER_COUNT }; @@ -52,6 +53,12 @@ static const unsigned int snudown_default_md_flags = MKDEXT_STRIKETHROUGH | MKDEXT_TABLES; +static const unsigned int snudown_default_md_flags_without_links = + MKDEXT_NO_INTRA_EMPHASIS | + MKDEXT_SUPERSCRIPT | + MKDEXT_STRIKETHROUGH | + MKDEXT_TABLES; + static const unsigned int snudown_default_render_flags = HTML_SKIP_HTML | HTML_SKIP_IMAGES | @@ -123,6 +130,14 @@ void init_wiki_renderer(PyObject *module) { sundown[RENDERER_WIKI].toc_state = &wiki_toc_state; } +void init_default_renderer_without_links(PyObject *module) { + PyModule_AddIntConstant(module, "RENDERER_USERTEXT_WITHOUTLINKS", RENDERER_USERTEXT_WITHOUTLINKS); + sundown[RENDERER_USERTEXT_WITHOUTLINKS].main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 0); + sundown[RENDERER_USERTEXT_WITHOUTLINKS].toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 1); + sundown[RENDERER_USERTEXT_WITHOUTLINKS].state = &usertext_state; + sundown[RENDERER_USERTEXT_WITHOUTLINKS].toc_state = &usertext_toc_state; +} + static PyObject * snudown_md(PyObject *self, PyObject *args, PyObject *kwargs) { @@ -206,6 +221,7 @@ PyMODINIT_FUNC initsnudown(void) init_default_renderer(module); init_wiki_renderer(module); + init_default_renderer_without_links(module); /* Version */ PyModule_AddStringConstant(module, "__version__", SNUDOWN_VERSION); diff --git a/test_snudown.py b/test_snudown.py index fa9568f..d0d0cb3 100644 --- a/test_snudown.py +++ b/test_snudown.py @@ -422,6 +422,64 @@ '

\n', } + +no_links_cases = { + 'http://www.reddit.com': + '

http://www.reddit.com

\n', + + 'http://www.reddit.com/a\x00b': + '

http://www.reddit.com/ab

\n', + + 'ampersands http://www.google.com?test&blah': + '

ampersands http://www.google.com?test&blah

\n', + + 'www.http://example.com/': + '

www.http://example.com/

\n', + + 'foo@example.com': + '

foo@example.com

\n', + + '/u/test/m/test test': + '

/u/test/m/test test

\n', + + '/u/test': + '

/u/test

\n', + + '/r/not.cool': + '

/r/not.cool

\n', + + 'u/test': + '

u/test

\n', + + '/r/whatever: fork': + '

/r/whatever: fork

\n', + + '/r/t:timereddit': + '

/r/t:timereddit

\n', + + '/r/reddit.com': + '

/r/reddit.com

\n', + + 'r/not.cool': + '

r/not.cool

\n', + + '/r/very+clever+multireddit+reddit.com+t:fork+yay': + '

/r/very+clever+multireddit+reddit.com+t:fork+yay

\n', + + '/r/t:heatdeathoftheuniverse': + '

/r/t:heatdeathoftheuniverse

\n', + + '/r/all-minus-something': + '

/r/all-minus-something

\n', + + r'escaped \/r/test': + '

escaped /r/test

\n', + + 'Words words /r/test words': + '

Words words /r/test words

\n', +} + + class SnudownTestCase(unittest.TestCase): def __init__(self, renderer=snudown.RENDERER_USERTEXT): self.renderer = renderer @@ -458,4 +516,10 @@ def test_snudown(): case.expected_output = expected_output suite.addTest(case) + for input, expected_output in no_links_cases.iteritems(): + case = SnudownTestCase(renderer=snudown.RENDERER_USERTEXT_WITHOUTLINKS) + case.input = input + case.expected_output = expected_output + suite.addTest(case) + return suite From d6e2afb5082ae98dae19ef4f5a7ae3992d833a85 Mon Sep 17 00:00:00 2001 From: debuggio Date: Fri, 10 Mar 2017 16:23:44 -0800 Subject: [PATCH 2/6] Added header for snudown to remove code duplication --- fuzzing/snudown-validator.c | 125 +----------------------------------- snudown.c | 122 +++++++---------------------------- snudown.h | 118 ++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 223 deletions(-) create mode 100644 snudown.h diff --git a/fuzzing/snudown-validator.c b/fuzzing/snudown-validator.c index f2c06d8..62de6e4 100644 --- a/fuzzing/snudown-validator.c +++ b/fuzzing/snudown-validator.c @@ -1,6 +1,7 @@ #include "markdown.h" #include "html.h" #include "buffer.h" +#include "../snudown.h" #include #include @@ -19,130 +20,6 @@ #define SNUDOWN_VERSION "1.3.2" -enum snudown_renderer_mode { - RENDERER_USERTEXT = 0, - RENDERER_WIKI, - RENDERER_USERTEXT_WITHOUTLINKS, - RENDERER_COUNT -}; - -struct snudown_renderopt { - struct html_renderopt html; - int nofollow; - const char *target; -}; - -struct snudown_renderer { - struct sd_markdown* main_renderer; - struct sd_markdown* toc_renderer; - struct module_state* state; - struct module_state* toc_state; -}; - -struct module_state { - struct sd_callbacks callbacks; - struct snudown_renderopt options; -}; - -static struct snudown_renderer sundown[RENDERER_COUNT]; - -static char* html_element_whitelist[] = {"tr", "th", "td", "table", "tbody", "thead", "tfoot", "caption", NULL}; -static char* html_attr_whitelist[] = {"colspan", "rowspan", "cellspacing", "cellpadding", "scope", NULL}; - -static struct module_state usertext_toc_state; -static struct module_state wiki_toc_state; -static struct module_state usertext_state; -static struct module_state wiki_state; - -static const unsigned int snudown_default_md_flags = - MKDEXT_NO_INTRA_EMPHASIS | - MKDEXT_SUPERSCRIPT | - MKDEXT_AUTOLINK | - MKDEXT_STRIKETHROUGH | - MKDEXT_TABLES; - -static const unsigned int snudown_default_md_flags_without_links = - MKDEXT_NO_INTRA_EMPHASIS | - MKDEXT_SUPERSCRIPT | - MKDEXT_STRIKETHROUGH | - MKDEXT_TABLES; - -static const unsigned int snudown_default_render_flags = - HTML_SKIP_HTML | - HTML_SKIP_IMAGES | - HTML_SAFELINK | - HTML_ESCAPE | - HTML_USE_XHTML; - -static const unsigned int snudown_wiki_render_flags = - HTML_SKIP_HTML | - HTML_SAFELINK | - HTML_ALLOW_ELEMENT_WHITELIST | - HTML_ESCAPE | - HTML_USE_XHTML; - -static void -snudown_link_attr(struct buf *ob, const struct buf *link, void *opaque) -{ - struct snudown_renderopt *options = opaque; - - if (options->nofollow) - BUFPUTSL(ob, " rel=\"nofollow\""); - - if (options->target != NULL) { - BUFPUTSL(ob, " target=\""); - bufputs(ob, options->target); - bufputc(ob, '\"'); - } -} - -static struct sd_markdown* make_custom_renderer(struct module_state* state, - const unsigned int renderflags, - const unsigned int markdownflags, - int toc_renderer) { - if(toc_renderer) { - sdhtml_toc_renderer(&state->callbacks, - (struct html_renderopt *)&state->options); - } else { - sdhtml_renderer(&state->callbacks, - (struct html_renderopt *)&state->options, - renderflags); - } - - state->options.html.link_attributes = &snudown_link_attr; - state->options.html.html_element_whitelist = html_element_whitelist; - state->options.html.html_attr_whitelist = html_attr_whitelist; - - return sd_markdown_new( - markdownflags, - 16, - 64, - &state->callbacks, - &state->options - ); -} - -void init_default_renderer() { - sundown[RENDERER_USERTEXT].main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags, 0); - sundown[RENDERER_USERTEXT].toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags, 1); - sundown[RENDERER_USERTEXT].state = &usertext_state; - sundown[RENDERER_USERTEXT].toc_state = &usertext_toc_state; -} - -void init_wiki_renderer() { - sundown[RENDERER_WIKI].main_renderer = make_custom_renderer(&wiki_state, snudown_wiki_render_flags, snudown_default_md_flags, 0); - sundown[RENDERER_WIKI].toc_renderer = make_custom_renderer(&wiki_toc_state, snudown_wiki_render_flags, snudown_default_md_flags, 1); - sundown[RENDERER_WIKI].state = &wiki_state; - sundown[RENDERER_WIKI].toc_state = &wiki_toc_state; -} - -void init_default_renderer_without_links() { - sundown[RENDERER_USERTEXT_WITHOUTLINKS].main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 0); - sundown[RENDERER_USERTEXT_WITHOUTLINKS].toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 1); - sundown[RENDERER_USERTEXT_WITHOUTLINKS].state = &usertext_state; - sundown[RENDERER_USERTEXT_WITHOUTLINKS].toc_state = &usertext_toc_state; -} - void snudown_md(struct buf *ob, const uint8_t *document, size_t doc_size, int wiki_mode) { diff --git a/snudown.c b/snudown.c index be4ae27..8365d6c 100644 --- a/snudown.c +++ b/snudown.c @@ -2,77 +2,15 @@ #include #include "markdown.h" -#include "html.h" #include "autolink.h" +#include "snudown.h" #define SNUDOWN_VERSION "1.4.0" -enum snudown_renderer_mode { - RENDERER_USERTEXT = 0, - RENDERER_WIKI, - RENDERER_USERTEXT_WITHOUTLINKS, - RENDERER_COUNT -}; - -struct snudown_renderopt { - struct html_renderopt html; - int nofollow; - const char *target; -}; - -struct snudown_renderer { - struct sd_markdown* main_renderer; - struct sd_markdown* toc_renderer; - struct module_state* state; - struct module_state* toc_state; -}; - -struct module_state { - struct sd_callbacks callbacks; - struct snudown_renderopt options; -}; - -static struct snudown_renderer sundown[RENDERER_COUNT]; - -static char* html_element_whitelist[] = {"tr", "th", "td", "table", "tbody", "thead", "tfoot", "caption", NULL}; -static char* html_attr_whitelist[] = {"colspan", "rowspan", "cellspacing", "cellpadding", "scope", NULL}; - -static struct module_state usertext_toc_state; -static struct module_state wiki_toc_state; -static struct module_state usertext_state; -static struct module_state wiki_state; - /* The module doc strings */ PyDoc_STRVAR(snudown_module__doc__, "When does the narwhal bacon? At Sundown."); PyDoc_STRVAR(snudown_md__doc__, "Render a Markdown document"); -static const unsigned int snudown_default_md_flags = - MKDEXT_NO_INTRA_EMPHASIS | - MKDEXT_SUPERSCRIPT | - MKDEXT_AUTOLINK | - MKDEXT_STRIKETHROUGH | - MKDEXT_TABLES; - -static const unsigned int snudown_default_md_flags_without_links = - MKDEXT_NO_INTRA_EMPHASIS | - MKDEXT_SUPERSCRIPT | - MKDEXT_STRIKETHROUGH | - MKDEXT_TABLES; - -static const unsigned int snudown_default_render_flags = - HTML_SKIP_HTML | - HTML_SKIP_IMAGES | - HTML_SAFELINK | - HTML_ESCAPE | - HTML_USE_XHTML; - -static const unsigned int snudown_wiki_render_flags = - HTML_SKIP_HTML | - HTML_SAFELINK | - HTML_ALLOW_ELEMENT_WHITELIST | - HTML_ESCAPE | - HTML_USE_XHTML; - static void snudown_link_attr(struct buf *ob, const struct buf *link, void *opaque) { @@ -88,56 +26,42 @@ snudown_link_attr(struct buf *ob, const struct buf *link, void *opaque) } } -static struct sd_markdown* make_custom_renderer(struct module_state* state, - const unsigned int renderflags, - const unsigned int markdownflags, - int toc_renderer) { - if(toc_renderer) { - sdhtml_toc_renderer(&state->callbacks, - (struct html_renderopt *)&state->options); - } else { - sdhtml_renderer(&state->callbacks, - (struct html_renderopt *)&state->options, - renderflags); - } - - state->options.html.link_attributes = &snudown_link_attr; - state->options.html.html_element_whitelist = html_element_whitelist; - state->options.html.html_attr_whitelist = html_attr_whitelist; - - return sd_markdown_new( - markdownflags, - 16, - 64, - &state->callbacks, - &state->options - ); -} - -void init_default_renderer(PyObject *module) { - PyModule_AddIntConstant(module, "RENDERER_USERTEXT", RENDERER_USERTEXT); +void init_default_renderer() { sundown[RENDERER_USERTEXT].main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags, 0); sundown[RENDERER_USERTEXT].toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags, 1); sundown[RENDERER_USERTEXT].state = &usertext_state; sundown[RENDERER_USERTEXT].toc_state = &usertext_toc_state; } -void init_wiki_renderer(PyObject *module) { - PyModule_AddIntConstant(module, "RENDERER_WIKI", RENDERER_WIKI); +void init_wiki_renderer() { sundown[RENDERER_WIKI].main_renderer = make_custom_renderer(&wiki_state, snudown_wiki_render_flags, snudown_default_md_flags, 0); sundown[RENDERER_WIKI].toc_renderer = make_custom_renderer(&wiki_toc_state, snudown_wiki_render_flags, snudown_default_md_flags, 1); sundown[RENDERER_WIKI].state = &wiki_state; sundown[RENDERER_WIKI].toc_state = &wiki_toc_state; } -void init_default_renderer_without_links(PyObject *module) { - PyModule_AddIntConstant(module, "RENDERER_USERTEXT_WITHOUTLINKS", RENDERER_USERTEXT_WITHOUTLINKS); +void init_default_renderer_without_links() { sundown[RENDERER_USERTEXT_WITHOUTLINKS].main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 0); sundown[RENDERER_USERTEXT_WITHOUTLINKS].toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 1); sundown[RENDERER_USERTEXT_WITHOUTLINKS].state = &usertext_state; sundown[RENDERER_USERTEXT_WITHOUTLINKS].toc_state = &usertext_toc_state; } +void register_default_renderer(PyObject *module) { + PyModule_AddIntConstant(module, "RENDERER_USERTEXT", RENDERER_USERTEXT); + init_default_renderer(); +} + +void register_wiki_renderer(PyObject *module) { + PyModule_AddIntConstant(module, "RENDERER_WIKI", RENDERER_WIKI); + init_wiki_renderer(); +} + +void register_default_renderer_without_links(PyObject *module) { + PyModule_AddIntConstant(module, "RENDERER_USERTEXT_WITHOUTLINKS", RENDERER_USERTEXT_WITHOUTLINKS); + init_default_renderer_without_links(); +} + static PyObject * snudown_md(PyObject *self, PyObject *args, PyObject *kwargs) { @@ -219,10 +143,10 @@ PyMODINIT_FUNC initsnudown(void) if (module == NULL) return; - init_default_renderer(module); - init_wiki_renderer(module); - init_default_renderer_without_links(module); + register_default_renderer(module); + register_wiki_renderer(module); + register_default_renderer_without_links(module); /* Version */ PyModule_AddStringConstant(module, "__version__", SNUDOWN_VERSION); -} +} \ No newline at end of file diff --git a/snudown.h b/snudown.h new file mode 100644 index 0000000..cfa95d1 --- /dev/null +++ b/snudown.h @@ -0,0 +1,118 @@ +/* snudown.h - header for snudown */ + +/* +* Copyright (c) 2017, Evgenii Timofeev +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +#include "html/html.h" + +enum snudown_renderer_mode { + RENDERER_USERTEXT = 0, + RENDERER_WIKI, + RENDERER_USERTEXT_WITHOUTLINKS, + RENDERER_COUNT +}; + +struct snudown_renderopt { + struct html_renderopt html; + int nofollow; + const char *target; +}; + +struct snudown_renderer { + struct sd_markdown* main_renderer; + struct sd_markdown* toc_renderer; + struct module_state* state; + struct module_state* toc_state; +}; + +struct module_state { + struct sd_callbacks callbacks; + struct snudown_renderopt options; +}; + +static char* html_element_whitelist[] = { "tr", "th", "td", "table", "tbody", "thead", "tfoot", "caption", NULL }; +static char* html_attr_whitelist[] = { "colspan", "rowspan", "cellspacing", "cellpadding", "scope", NULL }; + +static const unsigned int snudown_default_md_flags = + MKDEXT_NO_INTRA_EMPHASIS | + MKDEXT_SUPERSCRIPT | + MKDEXT_AUTOLINK | + MKDEXT_STRIKETHROUGH | + MKDEXT_TABLES; + +static const unsigned int snudown_default_md_flags_without_links = + MKDEXT_NO_INTRA_EMPHASIS | + MKDEXT_SUPERSCRIPT | + MKDEXT_STRIKETHROUGH | + MKDEXT_TABLES; + +static const unsigned int snudown_default_render_flags = + HTML_SKIP_HTML | + HTML_SKIP_IMAGES | + HTML_SAFELINK | + HTML_ESCAPE | + HTML_USE_XHTML; + +static const unsigned int snudown_wiki_render_flags = + HTML_SKIP_HTML | + HTML_SAFELINK | + HTML_ALLOW_ELEMENT_WHITELIST | + HTML_ESCAPE | + HTML_USE_XHTML; + +static struct snudown_renderer sundown[RENDERER_COUNT]; + +static struct module_state usertext_toc_state; +static struct module_state wiki_toc_state; +static struct module_state usertext_state; +static struct module_state wiki_state; + +static void snudown_link_attr(struct buf *ob, const struct buf *link, void *opaque); + +static struct sd_markdown* make_custom_renderer(struct module_state* state, + const unsigned int renderflags, + const unsigned int markdownflags, + int toc_renderer) { + if (toc_renderer) { + sdhtml_toc_renderer(&state->callbacks, + (struct html_renderopt *)&state->options); + } + else { + sdhtml_renderer(&state->callbacks, + (struct html_renderopt *)&state->options, + renderflags); + } + + state->options.html.link_attributes = &snudown_link_attr; + state->options.html.html_element_whitelist = html_element_whitelist; + state->options.html.html_attr_whitelist = html_attr_whitelist; + + return sd_markdown_new( + markdownflags, + 16, + 64, + &state->callbacks, + &state->options + ); +} + +extern void +init_default_renderer(void); + +extern void +init_wiki_renderer(void); + +extern void +init_default_renderer_without_links(void); \ No newline at end of file From 395c8e56f550f3e9aa0e33de00429fdc21de47dc Mon Sep 17 00:00:00 2001 From: debuggio Date: Tue, 28 Mar 2017 10:23:06 -0700 Subject: [PATCH 3/6] Code review fixes and refactoring --- fuzzing/CMakeLists.txt | 6 ++- snudown.c | 48 ++++-------------- src/markdown.c | 5 +- src/renderers.c | 98 ++++++++++++++++++++++++++++++++++++ snudown.h => src/renderers.h | 55 ++++---------------- test_snudown.py | 8 ++- 6 files changed, 131 insertions(+), 89 deletions(-) create mode 100644 src/renderers.c rename snudown.h => src/renderers.h (62%) diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 5ed60de..54213b8 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -8,7 +8,8 @@ set(HEADERS ../src/html_blocks.h ../src/html_entities.h ../src/markdown.h - ../src/stack.h + ../src/stack.h + ../src/renderers.h ) set(LIBRARY_SOURCES ../html/houdini_href_e.c @@ -18,7 +19,8 @@ set(LIBRARY_SOURCES ../src/autolink.c ../src/buffer.c ../src/markdown.c - ../src/stack.c + ../src/stack.c + ../src/renderers.c ${HEADERS} ) diff --git a/snudown.c b/snudown.c index 8365d6c..897d0b0 100644 --- a/snudown.c +++ b/snudown.c @@ -3,63 +3,33 @@ #include "markdown.h" #include "autolink.h" +#include "renderers.h" #include "snudown.h" -#define SNUDOWN_VERSION "1.4.0" +#define SNUDOWN_VERSION "1.5.0" /* The module doc strings */ PyDoc_STRVAR(snudown_module__doc__, "When does the narwhal bacon? At Sundown."); PyDoc_STRVAR(snudown_md__doc__, "Render a Markdown document"); -static void -snudown_link_attr(struct buf *ob, const struct buf *link, void *opaque) -{ - struct snudown_renderopt *options = opaque; - - if (options->nofollow) - BUFPUTSL(ob, " rel=\"nofollow\""); - - if (options->target != NULL) { - BUFPUTSL(ob, " target=\""); - bufputs(ob, options->target); - bufputc(ob, '\"'); - } -} - -void init_default_renderer() { - sundown[RENDERER_USERTEXT].main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags, 0); - sundown[RENDERER_USERTEXT].toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags, 1); - sundown[RENDERER_USERTEXT].state = &usertext_state; - sundown[RENDERER_USERTEXT].toc_state = &usertext_toc_state; -} - -void init_wiki_renderer() { - sundown[RENDERER_WIKI].main_renderer = make_custom_renderer(&wiki_state, snudown_wiki_render_flags, snudown_default_md_flags, 0); - sundown[RENDERER_WIKI].toc_renderer = make_custom_renderer(&wiki_toc_state, snudown_wiki_render_flags, snudown_default_md_flags, 1); - sundown[RENDERER_WIKI].state = &wiki_state; - sundown[RENDERER_WIKI].toc_state = &wiki_toc_state; -} - -void init_default_renderer_without_links() { - sundown[RENDERER_USERTEXT_WITHOUTLINKS].main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 0); - sundown[RENDERER_USERTEXT_WITHOUTLINKS].toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 1); - sundown[RENDERER_USERTEXT_WITHOUTLINKS].state = &usertext_state; - sundown[RENDERER_USERTEXT_WITHOUTLINKS].toc_state = &usertext_toc_state; -} +static struct snudown_renderer sundown[RENDERER_COUNT]; void register_default_renderer(PyObject *module) { PyModule_AddIntConstant(module, "RENDERER_USERTEXT", RENDERER_USERTEXT); - init_default_renderer(); + struct snudown_renderer *renderer = get_default_renderer(); + sundown[RENDERER_USERTEXT] = *renderer; } void register_wiki_renderer(PyObject *module) { PyModule_AddIntConstant(module, "RENDERER_WIKI", RENDERER_WIKI); - init_wiki_renderer(); + struct snudown_renderer *renderer = get_wiki_renderer(); + sundown[RENDERER_WIKI] = *renderer; } void register_default_renderer_without_links(PyObject *module) { PyModule_AddIntConstant(module, "RENDERER_USERTEXT_WITHOUTLINKS", RENDERER_USERTEXT_WITHOUTLINKS); - init_default_renderer_without_links(); + struct snudown_renderer *renderer = get_default_renderer_without_links(); + sundown[RENDERER_USERTEXT_WITHOUTLINKS] = *renderer; } static PyObject * diff --git a/src/markdown.c b/src/markdown.c index abe4a1d..44ccf45 100644 --- a/src/markdown.c +++ b/src/markdown.c @@ -2530,9 +2530,6 @@ sd_markdown_new( if (md->cb.linebreak) md->active_char['\n'] = MD_CHAR_LINEBREAK; - if (md->cb.image || md->cb.link) - md->active_char['['] = MD_CHAR_LINK; - md->active_char['<'] = MD_CHAR_LANGLE; md->active_char['\\'] = MD_CHAR_ESCAPE; md->active_char['&'] = MD_CHAR_ENTITITY; @@ -2540,6 +2537,8 @@ sd_markdown_new( if (extensions & MKDEXT_AUTOLINK) { if (!(extensions & MKDEXT_NO_EMAIL_AUTOLINK)) md->active_char['@'] = MD_CHAR_AUTOLINK_EMAIL; + if (md->cb.image || md->cb.link) + md->active_char['['] = MD_CHAR_LINK; md->active_char[':'] = MD_CHAR_AUTOLINK_URL; md->active_char['w'] = MD_CHAR_AUTOLINK_WWW; md->active_char['/'] = MD_CHAR_AUTOLINK_SUBREDDIT_OR_USERNAME; diff --git a/src/renderers.c b/src/renderers.c new file mode 100644 index 0000000..8afb28f --- /dev/null +++ b/src/renderers.c @@ -0,0 +1,98 @@ +#include "markdown.h" +#include "../html/html.h" +#include "renderers.h" + +static struct module_state usertext_toc_state; +static struct module_state wiki_toc_state; +static struct module_state usertext_state; +static struct module_state wiki_state; + +static struct sd_markdown *make_custom_renderer(struct module_state *state, + const unsigned int renderflags, + const unsigned int markdownflags, + int toc_renderer) { + if (toc_renderer) { + sdhtml_toc_renderer(&state->callbacks, + (struct html_renderopt *)&state->options); + } + else { + sdhtml_renderer(&state->callbacks, + (struct html_renderopt *)&state->options, + renderflags); + } + + state->options.html.link_attributes = &snudown_link_attr; + state->options.html.html_element_whitelist = html_element_whitelist; + state->options.html.html_attr_whitelist = html_attr_whitelist; + + return sd_markdown_new( + markdownflags, + 16, + 64, + &state->callbacks, + &state->options + ); +} + +struct snudown_renderer *get_default_renderer() { + struct snudown_renderer *sr = NULL; + + sr = calloc(1, sizeof(struct snudown_renderer)); + + if (!sr) + return NULL; + + sr->main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags, 0); + sr->toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags, 1); + sr->state = &usertext_state; + sr->toc_state = &usertext_toc_state; + + return sr; +} + +struct snudown_renderer *get_wiki_renderer() { + struct snudown_renderer *sr = NULL; + + sr = calloc(1, sizeof(struct snudown_renderer)); + + if (!sr) + return NULL; + + sr->main_renderer = make_custom_renderer(&wiki_state, snudown_wiki_render_flags, snudown_default_md_flags, 0); + sr->toc_renderer = make_custom_renderer(&wiki_toc_state, snudown_wiki_render_flags, snudown_default_md_flags, 1); + sr->state = &wiki_state; + sr->toc_state = &wiki_toc_state; + + return sr; +} + +struct snudown_renderer *get_default_renderer_without_links() { + struct snudown_renderer *sr = NULL; + + sr = calloc(1, sizeof(struct snudown_renderer)); + + if (!sr) + return NULL; + + sr->main_renderer = make_custom_renderer(&usertext_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 0); + sr->toc_renderer = make_custom_renderer(&usertext_toc_state, snudown_default_render_flags, snudown_default_md_flags_without_links, 1); + sr->state = &usertext_state; + sr->toc_state = &usertext_toc_state; + + return sr; +} + +static void +snudown_link_attr(struct buf *ob, const struct buf *link, void *opaque) +{ + struct snudown_renderopt *options = opaque; + + if (options->nofollow) + BUFPUTSL(ob, " rel=\"nofollow\""); + + if (options->target != NULL) { + BUFPUTSL(ob, " target=\""); + bufputs(ob, options->target); + bufputc(ob, '\"'); + } +} \ No newline at end of file diff --git a/snudown.h b/src/renderers.h similarity index 62% rename from snudown.h rename to src/renderers.h index cfa95d1..a4d259b 100644 --- a/snudown.h +++ b/src/renderers.h @@ -1,7 +1,7 @@ -/* snudown.h - header for snudown */ +/* renderers.h - header for renderers */ /* -* Copyright (c) 2017, Evgenii Timofeev +* Copyright (c) 2017, Reddit * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,7 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "html/html.h" +#include "../html/html.h" enum snudown_renderer_mode { RENDERER_USERTEXT = 0, @@ -72,47 +72,14 @@ static const unsigned int snudown_wiki_render_flags = HTML_ESCAPE | HTML_USE_XHTML; -static struct snudown_renderer sundown[RENDERER_COUNT]; +static void +snudown_link_attr(struct buf *ob, const struct buf *link, void *opaque); -static struct module_state usertext_toc_state; -static struct module_state wiki_toc_state; -static struct module_state usertext_state; -static struct module_state wiki_state; +extern struct snudown_renderer * +get_default_renderer(void); -static void snudown_link_attr(struct buf *ob, const struct buf *link, void *opaque); +extern struct snudown_renderer * +get_wiki_renderer(void); -static struct sd_markdown* make_custom_renderer(struct module_state* state, - const unsigned int renderflags, - const unsigned int markdownflags, - int toc_renderer) { - if (toc_renderer) { - sdhtml_toc_renderer(&state->callbacks, - (struct html_renderopt *)&state->options); - } - else { - sdhtml_renderer(&state->callbacks, - (struct html_renderopt *)&state->options, - renderflags); - } - - state->options.html.link_attributes = &snudown_link_attr; - state->options.html.html_element_whitelist = html_element_whitelist; - state->options.html.html_attr_whitelist = html_attr_whitelist; - - return sd_markdown_new( - markdownflags, - 16, - 64, - &state->callbacks, - &state->options - ); -} - -extern void -init_default_renderer(void); - -extern void -init_wiki_renderer(void); - -extern void -init_default_renderer_without_links(void); \ No newline at end of file +extern struct snudown_renderer * +get_default_renderer_without_links(void); \ No newline at end of file diff --git a/test_snudown.py b/test_snudown.py index d0d0cb3..990233f 100644 --- a/test_snudown.py +++ b/test_snudown.py @@ -437,7 +437,13 @@ '

www.http://example.com/

\n', 'foo@example.com': - '

foo@example.com

\n', + '

foo@example.com

\n', + + '[foo](/u/bar)': + '

[foo](/u/bar)

\n', + + '': + '

</u/foobar>

\n', '/u/test/m/test test': '

/u/test/m/test test

\n', From b2e380a4db6d50e2dc4f8fdb588e14457dcf2b66 Mon Sep 17 00:00:00 2001 From: debuggio Date: Tue, 28 Mar 2017 17:36:25 -0700 Subject: [PATCH 4/6] minor refactoring in renderers --- snudown.c | 1 - src/markdown.c | 5 +++-- src/renderers.c | 2 ++ src/renderers.h | 3 --- test_snudown.py | 6 +++--- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/snudown.c b/snudown.c index 897d0b0..0262143 100644 --- a/snudown.c +++ b/snudown.c @@ -4,7 +4,6 @@ #include "markdown.h" #include "autolink.h" #include "renderers.h" -#include "snudown.h" #define SNUDOWN_VERSION "1.5.0" diff --git a/src/markdown.c b/src/markdown.c index 44ccf45..abe4a1d 100644 --- a/src/markdown.c +++ b/src/markdown.c @@ -2530,6 +2530,9 @@ sd_markdown_new( if (md->cb.linebreak) md->active_char['\n'] = MD_CHAR_LINEBREAK; + if (md->cb.image || md->cb.link) + md->active_char['['] = MD_CHAR_LINK; + md->active_char['<'] = MD_CHAR_LANGLE; md->active_char['\\'] = MD_CHAR_ESCAPE; md->active_char['&'] = MD_CHAR_ENTITITY; @@ -2537,8 +2540,6 @@ sd_markdown_new( if (extensions & MKDEXT_AUTOLINK) { if (!(extensions & MKDEXT_NO_EMAIL_AUTOLINK)) md->active_char['@'] = MD_CHAR_AUTOLINK_EMAIL; - if (md->cb.image || md->cb.link) - md->active_char['['] = MD_CHAR_LINK; md->active_char[':'] = MD_CHAR_AUTOLINK_URL; md->active_char['w'] = MD_CHAR_AUTOLINK_WWW; md->active_char['/'] = MD_CHAR_AUTOLINK_SUBREDDIT_OR_USERNAME; diff --git a/src/renderers.c b/src/renderers.c index 8afb28f..6b9c735 100644 --- a/src/renderers.c +++ b/src/renderers.c @@ -6,6 +6,8 @@ static struct module_state usertext_toc_state; static struct module_state wiki_toc_state; static struct module_state usertext_state; static struct module_state wiki_state; +static char* html_element_whitelist[] = { "tr", "th", "td", "table", "tbody", "thead", "tfoot", "caption", NULL }; +static char* html_attr_whitelist[] = { "colspan", "rowspan", "cellspacing", "cellpadding", "scope", NULL }; static struct sd_markdown *make_custom_renderer(struct module_state *state, const unsigned int renderflags, diff --git a/src/renderers.h b/src/renderers.h index a4d259b..9780dcb 100644 --- a/src/renderers.h +++ b/src/renderers.h @@ -42,9 +42,6 @@ struct module_state { struct snudown_renderopt options; }; -static char* html_element_whitelist[] = { "tr", "th", "td", "table", "tbody", "thead", "tfoot", "caption", NULL }; -static char* html_attr_whitelist[] = { "colspan", "rowspan", "cellspacing", "cellpadding", "scope", NULL }; - static const unsigned int snudown_default_md_flags = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_SUPERSCRIPT | diff --git a/test_snudown.py b/test_snudown.py index 990233f..9b1316c 100644 --- a/test_snudown.py +++ b/test_snudown.py @@ -423,7 +423,7 @@ } -no_links_cases = { +no_autolinks_cases = { 'http://www.reddit.com': '

http://www.reddit.com

\n', @@ -440,7 +440,7 @@ '

foo@example.com

\n', '[foo](/u/bar)': - '

[foo](/u/bar)

\n', + '

foo

\n', '': '

</u/foobar>

\n', @@ -522,7 +522,7 @@ def test_snudown(): case.expected_output = expected_output suite.addTest(case) - for input, expected_output in no_links_cases.iteritems(): + for input, expected_output in no_autolinks_cases.iteritems(): case = SnudownTestCase(renderer=snudown.RENDERER_USERTEXT_WITHOUTLINKS) case.input = input case.expected_output = expected_output From a7375dc394ab220763e87bb356a85c445ec6267a Mon Sep 17 00:00:00 2001 From: debuggio Date: Thu, 20 Apr 2017 11:31:41 -0700 Subject: [PATCH 5/6] Removed include of unexisting file from snudown-validator --- fuzzing/snudown-validator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzing/snudown-validator.c b/fuzzing/snudown-validator.c index 62de6e4..de7d890 100644 --- a/fuzzing/snudown-validator.c +++ b/fuzzing/snudown-validator.c @@ -1,7 +1,7 @@ #include "markdown.h" #include "html.h" #include "buffer.h" -#include "../snudown.h" +#include "../src/renderers.h" #include #include From 877d9f67387d3dd58d26314863c946048112a5ec Mon Sep 17 00:00:00 2001 From: debuggio Date: Thu, 27 Apr 2017 09:04:02 -0700 Subject: [PATCH 6/6] Fix for snudown-validator --- fuzzing/snudown-validator.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fuzzing/snudown-validator.c b/fuzzing/snudown-validator.c index de7d890..c12b022 100644 --- a/fuzzing/snudown-validator.c +++ b/fuzzing/snudown-validator.c @@ -20,6 +20,23 @@ #define SNUDOWN_VERSION "1.3.2" +static struct snudown_renderer sundown[RENDERER_COUNT]; + +void init_default_renderer() { + struct snudown_renderer *renderer = get_default_renderer(); + sundown[RENDERER_USERTEXT] = *renderer; +} + +void init_wiki_renderer() { + struct snudown_renderer *renderer = get_wiki_renderer(); + sundown[RENDERER_WIKI] = *renderer; +} + +void init_default_renderer_without_links() { + struct snudown_renderer *renderer = get_default_renderer_without_links(); + sundown[RENDERER_USERTEXT_WITHOUTLINKS] = *renderer; +} + void snudown_md(struct buf *ob, const uint8_t *document, size_t doc_size, int wiki_mode) {