1 /*============================================================================= 2 Copyright (c) 2011-2013 Daniel James 3 4 Use, modification and distribution is subject to the Boost Software 5 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 6 http://www.boost.org/LICENSE_1_0.txt) 7 =============================================================================*/ 8 9 #include <boost/range/algorithm/find.hpp> 10 #include <boost/range/algorithm/sort.hpp> 11 #include "document_state_impl.hpp" 12 #include "simple_parse.hpp" 13 #include "utils.hpp" 14 15 namespace quickbook 16 { 17 namespace 18 { 19 char const* id_attributes_[] = {"id", "linkend", "linkends", 20 "arearefs"}; 21 } 22 xml_processor()23 xml_processor::xml_processor() 24 { 25 static std::size_t const n_id_attributes = 26 sizeof(id_attributes_) / sizeof(char const*); 27 for (int i = 0; i != n_id_attributes; ++i) { 28 id_attributes.push_back(id_attributes_[i]); 29 } 30 31 boost::sort(id_attributes); 32 } 33 parse(quickbook::string_view source,callback & c)34 void xml_processor::parse(quickbook::string_view source, callback& c) 35 { 36 typedef string_iterator iterator; 37 38 c.start(source); 39 40 iterator it = source.begin(), end = source.end(); 41 42 for (;;) { 43 read_past(it, end, "<"); 44 if (it == end) break; 45 46 if (read(it, end, "!--quickbook-escape-prefix-->")) { 47 read_past(it, end, "<!--quickbook-escape-postfix-->"); 48 continue; 49 } 50 51 switch (*it) { 52 case '?': 53 ++it; 54 read_past(it, end, "?>"); 55 break; 56 57 case '!': 58 if (read(it, end, "!--")) 59 read_past(it, end, "-->"); 60 else 61 read_past(it, end, ">"); 62 break; 63 64 default: 65 if ((*it >= 'a' && *it <= 'z') || (*it >= 'A' && *it <= 'Z') || 66 *it == '_' || *it == ':') { 67 read_to_one_of(it, end, " \t\n\r>"); 68 69 for (;;) { 70 read_some_of(it, end, " \t\n\r"); 71 iterator name_start = it; 72 read_to_one_of(it, end, "= \t\n\r>"); 73 if (it == end || *it == '>') break; 74 quickbook::string_view name( 75 name_start, it - name_start); 76 ++it; 77 78 read_some_of(it, end, "= \t\n\r"); 79 if (it == end || (*it != '"' && *it != '\'')) break; 80 81 char delim = *it; 82 ++it; 83 84 iterator value_start = it; 85 86 it = std::find(it, end, delim); 87 if (it == end) break; 88 quickbook::string_view value( 89 value_start, it - value_start); 90 ++it; 91 92 if (boost::find(id_attributes, name.to_s()) != 93 id_attributes.end()) { 94 c.id_value(value); 95 } 96 } 97 } 98 else { 99 read_past(it, end, ">"); 100 } 101 } 102 } 103 104 c.finish(source); 105 } 106 107 namespace detail 108 { linkify(quickbook::string_view source,quickbook::string_view linkend)109 std::string linkify( 110 quickbook::string_view source, quickbook::string_view linkend) 111 { 112 typedef string_iterator iterator; 113 114 iterator it = source.begin(), end = source.end(); 115 116 bool contains_link = false; 117 118 for (; !contains_link;) { 119 read_past(it, end, "<"); 120 if (it == end) break; 121 122 switch (*it) { 123 case '?': 124 ++it; 125 read_past(it, end, "?>"); 126 break; 127 128 case '!': 129 if (read(it, end, "!--")) { 130 read_past(it, end, "-->"); 131 } 132 else { 133 read_past(it, end, ">"); 134 } 135 break; 136 137 default: 138 if ((*it >= 'a' && *it <= 'z') || 139 (*it >= 'A' && *it <= 'Z') || *it == '_' || 140 *it == ':') { 141 iterator tag_name_start = it; 142 read_to_one_of(it, end, " \t\n\r>"); 143 quickbook::string_view tag_name( 144 tag_name_start, it - tag_name_start); 145 if (tag_name == "link") { 146 contains_link = true; 147 } 148 149 for (;;) { 150 read_to_one_of(it, end, "\"'\n\r>"); 151 if (it == end || *it == '>') break; 152 if (*it == '"' || *it == '\'') { 153 char delim = *it; 154 ++it; 155 it = std::find(it, end, delim); 156 if (it == end) break; 157 ++it; 158 } 159 } 160 } 161 else { 162 read_past(it, end, ">"); 163 } 164 } 165 } 166 167 std::string result; 168 169 if (!contains_link) { 170 result += "<link linkend=\""; 171 result.append(linkend.begin(), linkend.end()); 172 result += "\">"; 173 result.append(source.begin(), source.end()); 174 result += "</link>"; 175 } 176 else { 177 result.append(source.begin(), source.end()); 178 } 179 180 return result; 181 } 182 } 183 } 184