Commit 44fc7cf20de463c6d59777fb2773b874a351b244

Martin Mitas 2017-08-30T16:06:44

Merge branch 'master' of https://github.com/mity/md4c

diff --git a/.travis.yml b/.travis.yml
index 4efe09b..fef67c0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,16 +6,25 @@ language: c
 compiler:
     - gcc
 
+addons:
+    apt:
+        packages:
+            - python3   # for running tests
+            - lcov      # for generating code coverage report
+
 before_script:
     - mkdir build
     - cd build
-    - CFLAGS='-g -O0 --coverage' cmake -G 'Unix Makefiles' ..
+    - CFLAGS='--coverage -g -O0' cmake -DCMAKE_BUILD_TYPE=Debug -G 'Unix Makefiles' ..
 
 script:
-    - make
+    - make VERBOSE=1
 
 after_success:
-    - sudo apt-get install python3
-    - pip install --user cpp-coveralls
     - ../scripts/run-tests.sh
-    - ~/.local/bin/coveralls -r .. --gcov-options '\-lp' -i md4c -i md2html
+    # Creating report
+    - lcov --directory . --capture --output-file coverage.info # capture coverage info
+    - lcov --remove coverage.info '/usr/*' --output-file coverage.info # filter out system
+    - lcov --list coverage.info # debug info
+    # Uploading report to CodeCov
+    - bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1b36196..a32d7d8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,10 +15,6 @@ endif()
 
 if(CMAKE_COMPILER_IS_GNUCC)
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
-
-    # By default, CMake uses -O3 for Release builds. Lets stick with safer -O2:
-    string(REGEX REPLACE "(^| )-O[0-9a-z]+" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
-    set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
 elseif(MSVC)
     # Disable warnings about the so-called unsecured functions:
     add_definitions(/D_CRT_SECURE_NO_WARNINGS)
diff --git a/README.md b/README.md
index 2853e6a..05be3a0 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 [![Build status (travis-ci.com)](https://img.shields.io/travis/mity/md4c/master.svg?label=linux%20build)](https://travis-ci.org/mity/md4c)
 [![Build status (appveyor.com)](https://img.shields.io/appveyor/ci/mity/md4c/master.svg?label=windows%20build)](https://ci.appveyor.com/project/mity/md4c/branch/master)
-[![Coverity Scan Build Status](https://img.shields.io/coverity/scan/mity-md4c.svg)](https://scan.coverity.com/projects/mity-md4c)
-[![Coverage](https://img.shields.io/coveralls/mity/md4c/master.svg)](https://coveralls.io/github/mity/md4c)
+[![Coverity Scan Build Status](https://img.shields.io/coverity/scan/mity-md4c.svg?label=coverity%20scan)](https://scan.coverity.com/projects/mity-md4c)
+[![Codecov](https://img.shields.io/codecov/c/github/mity/md4c/master.svg?label=code%20coverage)](https://codecov.io/github/mity/md4c)
 
 # MD4C Readme
 
diff --git a/md2html/render_html.c b/md2html/render_html.c
index 6f91d0d..ca28089 100644
--- a/md2html/render_html.c
+++ b/md2html/render_html.c
@@ -49,6 +49,7 @@ struct MD_RENDER_HTML_tag {
     void (*process_output)(const MD_CHAR*, MD_SIZE, void*);
     void* userdata;
     unsigned flags;
+    int image_nesting_level;
 };
 
 
@@ -251,19 +252,17 @@ render_attribute(MD_RENDER_HTML* r, const MD_ATTRIBUTE* attr,
 }
 
 
-static int image_nesting_level = 0;
-
 static void
 render_open_ol_block(MD_RENDER_HTML* r, const MD_BLOCK_OL_DETAIL* det)
 {
     char buf[64];
 
     if(det->start == 1) {
-        RENDER_LITERAL(r, "<ol>");
+        RENDER_LITERAL(r, "<ol>\n");
         return;
     }
 
-    snprintf(buf, sizeof(buf), "<ol start=\"%u\">", det->start);
+    snprintf(buf, sizeof(buf), "<ol start=\"%u\">\n", det->start);
     RENDER_LITERAL(r, buf);
 }
 
@@ -318,7 +317,7 @@ render_open_img_span(MD_RENDER_HTML* r, const MD_SPAN_IMG_DETAIL* det)
 
     RENDER_LITERAL(r, "\" alt=\"");
 
-    image_nesting_level++;
+    r->image_nesting_level++;
 }
 
 static void
@@ -331,7 +330,7 @@ render_close_img_span(MD_RENDER_HTML* r, const MD_SPAN_IMG_DETAIL* det)
 
     RENDER_LITERAL(r, "\">");
 
-    image_nesting_level--;
+    r->image_nesting_level--;
 }
 
 
@@ -400,7 +399,7 @@ enter_span_callback(MD_SPANTYPE type, void* detail, void* userdata)
 {
     MD_RENDER_HTML* r = (MD_RENDER_HTML*) userdata;
 
-    if(image_nesting_level > 0) {
+    if(r->image_nesting_level > 0) {
         /* We are inside an image, i.e. rendering the ALT attribute of
          * <IMG> tag. */
         return 0;
@@ -423,10 +422,10 @@ leave_span_callback(MD_SPANTYPE type, void* detail, void* userdata)
 {
     MD_RENDER_HTML* r = (MD_RENDER_HTML*) userdata;
 
-    if(image_nesting_level > 0) {
+    if(r->image_nesting_level > 0) {
         /* We are inside an image, i.e. rendering the ALT attribute of
          * <IMG> tag. */
-        if(image_nesting_level == 1  &&  type == MD_SPAN_IMG)
+        if(r->image_nesting_level == 1  &&  type == MD_SPAN_IMG)
             render_close_img_span(r, (MD_SPAN_IMG_DETAIL*) detail);
         return 0;
     }
@@ -450,8 +449,8 @@ text_callback(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userdat
 
     switch(type) {
         case MD_TEXT_NULLCHAR:  render_utf8_codepoint(r, 0x0000, render_text); break;
-        case MD_TEXT_BR:        RENDER_LITERAL(r, (image_nesting_level == 0 ? "<br>\n" : " ")); break;
-        case MD_TEXT_SOFTBR:    RENDER_LITERAL(r, (image_nesting_level == 0 ? "\n" : " ")); break;
+        case MD_TEXT_BR:        RENDER_LITERAL(r, (r->image_nesting_level == 0 ? "<br>\n" : " ")); break;
+        case MD_TEXT_SOFTBR:    RENDER_LITERAL(r, (r->image_nesting_level == 0 ? "\n" : " ")); break;
         case MD_TEXT_HTML:      render_text(r, text, size); break;
         case MD_TEXT_ENTITY:    render_entity(r, text, size, render_html_escaped); break;
         default:                render_html_escaped(r, text, size); break;
@@ -473,7 +472,7 @@ md_render_html(const MD_CHAR* input, MD_SIZE input_size,
                void (*process_output)(const MD_CHAR*, MD_SIZE, void*),
                void* userdata, unsigned parser_flags, unsigned renderer_flags)
 {
-    MD_RENDER_HTML render = { process_output, userdata, renderer_flags };
+    MD_RENDER_HTML render = { process_output, userdata, renderer_flags, 0 };
 
     MD_RENDERER renderer = {
         enter_block_callback,
diff --git a/md4c/md4c.c b/md4c/md4c.c
index 0b10c72..7b2c186 100644
--- a/md4c/md4c.c
+++ b/md4c/md4c.c
@@ -1997,14 +1997,6 @@ md_is_link_destination_B(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end,
     return TRUE;
 }
 
-static inline int
-md_is_link_destination(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end,
-                       OFF* p_contents_beg, OFF* p_contents_end)
-{
-    return (md_is_link_destination_A(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end)  ||
-            md_is_link_destination_B(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end));
-}
-
 static int
 md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
                  OFF* p_end, int* p_beg_line_index, int* p_end_line_index,
@@ -2069,7 +2061,9 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
  * If there is an error (cannot alloc memory for storing it), we return -1.
  */
 static int
-md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
+md_is_link_reference_definition_helper(
+            MD_CTX* ctx, const MD_LINE* lines, int n_lines,
+            int (*is_link_dest_fn)(MD_CTX*, OFF, OFF, OFF*, OFF*, OFF*))
 {
     OFF label_contents_beg;
     OFF label_contents_end;
@@ -2113,8 +2107,8 @@ md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
     }
 
     /* Link destination. */
-    if(!md_is_link_destination(ctx, off, lines[line_index].end,
-                &off, &dest_contents_beg, &dest_contents_end))
+    if(!is_link_dest_fn(ctx, off, lines[line_index].end,
+                        &off, &dest_contents_beg, &dest_contents_end))
         return FALSE;
 
     /* (Optional) title. Note we interpret it as an title only if nothing
@@ -2200,6 +2194,16 @@ abort:
     return -1;
 }
 
+static inline int
+md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
+{
+    int ret;
+    ret = md_is_link_reference_definition_helper(ctx, lines, n_lines, md_is_link_destination_A);
+    if(ret == 0)
+        ret = md_is_link_reference_definition_helper(ctx, lines, n_lines, md_is_link_destination_B);
+    return ret;
+}
+
 static int
 md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
                      OFF beg, OFF end, MD_LINK_ATTR* attr)
@@ -2255,8 +2259,9 @@ abort:
 }
 
 static int
-md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
-                       OFF beg, OFF* p_end, MD_LINK_ATTR* attr)
+md_is_inline_link_spec_helper(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
+                              OFF beg, OFF* p_end, MD_LINK_ATTR* attr,
+                              int (*is_link_dest_fn)(MD_CTX*, OFF, OFF, OFF*, OFF*, OFF*))
 {
     int line_index = 0;
     int tmp_line_index;
@@ -2284,10 +2289,14 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
     }
 
     /* (Optional) link destination. */
-    if(!md_is_link_destination(ctx, off, lines[line_index].end,
-            &off, &attr->dest_beg, &attr->dest_end)) {
-        attr->dest_beg = off;
-        attr->dest_end = off;
+    if(!is_link_dest_fn(ctx, off, lines[line_index].end,
+                        &off, &attr->dest_beg, &attr->dest_end)) {
+        if(is_link_dest_fn == md_is_link_destination_B) {
+            attr->dest_beg = off;
+            attr->dest_end = off;
+        } else {
+            return FALSE;
+        }
     }
 
     /* (Optional) title. */
@@ -2341,6 +2350,14 @@ abort:
     return ret;
 }
 
+static inline int
+md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
+                       OFF beg, OFF* p_end, MD_LINK_ATTR* attr)
+{
+    return md_is_inline_link_spec_helper(ctx, lines, n_lines, beg, p_end, attr, md_is_link_destination_A) ||
+           md_is_inline_link_spec_helper(ctx, lines, n_lines, beg, p_end, attr, md_is_link_destination_B);
+}
+
 static void
 md_free_ref_defs(MD_CTX* ctx)
 {
diff --git a/test/coverage.txt b/test/coverage.txt
index 2a1be58..7a0ec5a 100644
--- a/test/coverage.txt
+++ b/test/coverage.txt
@@ -110,6 +110,13 @@ a*b**c*
 ````````````````````````````````
 
 
+### [Issue 24](https://github.com/mity/md4c/issues/24)
+```````````````````````````````` example
+[a](<b>c)
+.
+<p><a href="%3Cb%3Ec">a</a></p>
+````````````````````````````````
+
 
 ## Code coverage
 
diff --git a/test/pathological_tests.py b/test/pathological_tests.py
old mode 100644
new mode 100755
index 3adc97d..4f0e31b
--- a/test/pathological_tests.py
+++ b/test/pathological_tests.py
@@ -63,8 +63,8 @@ pathological = {
                  ("[t](/u) " * 50000,
                   re.compile("(<a href=\"/u\">t</a> ?){50000}")),
     "many references":
-                 ("".join(map(lambda x: ("[" + str(x) + "]: /url\n\n[0]\n\n"), range(1,65000))),
-                  re.compile("^(<p>\\[0\\]</p>\r?\n)*$")),
+                 ("".join(map(lambda x: ("[" + str(x) + "]: u\n"), range(1,50000 * 16))) + "[0] " * 50000,
+                  re.compile("(\[0\] ){49999}"))
     }
 
 whitespace_re = re.compile('/s+/')