• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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