diff --git a/src/actions.cpp b/src/actions.cpp
index eb78dd8..3693cd6 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -1754,10 +1754,7 @@ namespace quickbook
if (self_linked_headers && state.document.compatibility_version() >= 103)
{
- state.out << ""
- << content.get_encoded()
- << ""
- ;
+ state.out << quickbook::detail::linkify(content.get_encoded(), full_id);
}
else
{
diff --git a/src/id_xml.cpp b/src/id_xml.cpp
index 40f07f6..1b65417 100644
--- a/src/id_xml.cpp
+++ b/src/id_xml.cpp
@@ -150,4 +150,127 @@ namespace quickbook
c.finish(source);
}
+
+ namespace detail {
+ std::string linkify(quickbook::string_view source, quickbook::string_view linkend)
+ {
+ typedef quickbook::string_view::const_iterator iterator;
+
+ std::string result;
+
+ iterator it = source.begin(), end = source.end();
+
+ int link_depth = 0;
+ iterator start = it;
+ read_some_of(it, end, " \t\n\r");
+ result.append(start, it);
+ start = it;
+ // If the source is empty, we'll still create an empty link tag
+ // to avoid gratuitous changes in generated output, need to track
+ // that special case.
+ bool empty = true;
+
+ for(;;)
+ {
+ read_to_one_of(it, end, "<");
+ if (it == end) break;
+ iterator tag_start = it;
+ ++it;
+ if (it == end) break;
+
+ if (read(it, end, "!--quickbook-escape-prefix-->"))
+ {
+ read_past(it, end, "");
+ continue;
+ }
+
+ switch(*it)
+ {
+ case '?':
+ ++it;
+ read_past(it, end, "?>");
+ break;
+
+ case '!':
+ if (read(it, end, "!--")) {
+ read_past(it, end, "-->");
+ } else {
+ read_past(it, end, ">");
+ }
+ break;
+
+ case '/':
+ {
+ ++it;
+ read_some_of(it, end, " \t\n\r");
+ if (it == end) { break; }
+ iterator tag_name_start = it;
+ read_to_one_of(it, end, " \t\n\r>");
+ quickbook::string_view tag_name(tag_name_start, it - tag_name_start);
+ read_past(it, end, ">");
+
+ if (tag_name == "link") {
+ if (link_depth > 0) { --link_depth; }
+ if (link_depth == 0) {
+ read_some_of(it, end, " \t\n\r");
+ result.append(start, it);
+ start = it;
+ empty = false;
+ }
+ }
+ }
+ break;
+
+ default:
+ if ((*it >= 'a' && *it <= 'z') ||
+ (*it >= 'A' && *it <= 'Z') ||
+ *it == '_' || *it == ':')
+ {
+ iterator tag_name_start = it;
+ read_to_one_of(it, end, " \t\n\r>");
+ quickbook::string_view tag_name(tag_name_start, it - tag_name_start);
+
+ if (tag_name == "link") {
+ if (link_depth == 0 && start != tag_start) {
+ result += "";
+ result.append(start, tag_start);
+ result += "";
+ start = tag_start;
+ empty = false;
+ }
+ ++link_depth;
+ }
+
+ for (;;) {
+ read_to_one_of(it, end, "\"'\n\r>");
+ if (it == end || *it == '>') break;
+ if (*it == '"' || *it == '\'') {
+ char delim = *it;
+ ++it;
+ it = std::find(it, end, delim);
+ if (it == end) break;
+ ++it;
+ }
+ }
+ }
+ else
+ {
+ read_past(it, end, ">");
+ }
+ }
+ }
+
+ if (start != it || empty) {
+ result += "";
+ result.append(start, it);
+ result += "";
+ }
+
+ return result;
+ }
+ }
}
diff --git a/src/utils.hpp b/src/utils.hpp
index 93e7ed1..86163cf 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -49,6 +49,9 @@ namespace quickbook { namespace detail {
inline std::string to_s(quickbook::string_view x) {
return std::string(x.begin(), x.end());
}
+
+ // Defined in id_xml.cpp. Just because.
+ std::string linkify(quickbook::string_view source, quickbook::string_view linkend);
}}
#endif // BOOST_SPIRIT_QUICKBOOK_UTILS_HPP
diff --git a/test/section-1_7.gold b/test/section-1_7.gold
index 33c6767..4071386 100644
--- a/test/section-1_7.gold
+++ b/test/section-1_7.gold
@@ -23,4 +23,11 @@
Section with template in id
+
+
diff --git a/test/section-1_7.quickbook b/test/section-1_7.quickbook
index ada95a2..9c8baeb 100644
--- a/test/section-1_7.quickbook
+++ b/test/section-1_7.quickbook
@@ -16,3 +16,8 @@
[template thing[] abc]
[section:sect-[thing] Section with template in id]
[endsect]
+
+[section [link section_id_1_7.id_test1 Link in title]]
+[endsect]
+[section [link section_id_1_7.id_test1 Link] in title]
+[endsect]
diff --git a/test/unit/Jamfile.v2 b/test/unit/Jamfile.v2
index a7a3de0..f828b53 100644
--- a/test/unit/Jamfile.v2
+++ b/test/unit/Jamfile.v2
@@ -22,6 +22,7 @@ run values_test.cpp ../../src/values.cpp ../../src/files.cpp ;
run post_process_test.cpp ../../src/post_process.cpp ;
run source_map_test.cpp ../../src/files.cpp ;
run glob_test.cpp ../../src/glob.cpp ;
+run linkify_test.cpp ../../src/id_xml.cpp ;
# TODO: Reinstate this test? Too painful to run at the moment.
# run file_path_to_url_test.cpp ../../src/native_text.cpp ../../src/utils.cpp ;
diff --git a/test/unit/linkify_test.cpp b/test/unit/linkify_test.cpp
new file mode 100644
index 0000000..e597e7f
--- /dev/null
+++ b/test/unit/linkify_test.cpp
@@ -0,0 +1,30 @@
+
+/*=============================================================================
+ Copyright (c) 2017 Daniel James
+
+ Use, modification and distribution is subject to the Boost Software
+ License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+
+#include "utils.hpp"
+#include
+
+#include
+
+void linkify_test() {
+ using quickbook::detail::linkify;
+
+ BOOST_TEST(linkify("abc", "link") == "abc");
+ BOOST_TEST(linkify("abc", "link") ==
+ "abc");
+ BOOST_TEST(linkify("abc def", "link") ==
+ "abc def");
+ BOOST_TEST(linkify("abc def", "link") ==
+ "abc def");
+}
+
+int main() {
+ linkify_test();
+ return boost::report_errors();
+}