Imported Upstream version 1.57.0
[platform/upstream/boost.git] / tools / quickbook / src / id_xml.cpp
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 "document_state_impl.hpp"
10 #include "utils.hpp"
11 #include <boost/range/algorithm.hpp>
12
13 namespace quickbook
14 {
15     namespace
16     {
17         char const* id_attributes_[] =
18         {
19             "id",
20             "linkend",
21             "linkends",
22             "arearefs"
23         };
24     }
25
26     xml_processor::xml_processor()
27     {
28         static int const n_id_attributes = sizeof(id_attributes_)/sizeof(char const*);
29         for (int i = 0; i != n_id_attributes; ++i)
30         {
31             id_attributes.push_back(id_attributes_[i]);
32         }
33
34         boost::sort(id_attributes);
35     }
36
37     template <typename Iterator>
38     bool read(Iterator& it, Iterator end, char const* text)
39     {
40         for(Iterator it2 = it;; ++it2, ++text) {
41             if (!*text) {
42                 it = it2;
43                 return true;
44             }
45
46             if (it2 == end || *it2 != *text)
47                 return false;
48         }
49     }
50
51     template <typename Iterator>
52     void read_past(Iterator& it, Iterator end, char const* text)
53     {
54         while (it != end && !read(it, end, text)) ++it;
55     }
56
57     bool find_char(char const* text, char c)
58     {
59         for(;*text; ++text)
60             if (c == *text) return true;
61         return false;
62     }
63
64     template <typename Iterator>
65     void read_some_of(Iterator& it, Iterator end, char const* text)
66     {
67         while(it != end && find_char(text, *it)) ++it;
68     }
69
70     template <typename Iterator>
71     void read_to_one_of(Iterator& it, Iterator end, char const* text)
72     {
73         while(it != end && !find_char(text, *it)) ++it;
74     }
75
76     void xml_processor::parse(boost::string_ref source, callback& c)
77     {
78         typedef boost::string_ref::const_iterator iterator;
79
80         c.start(source);
81
82         iterator it = source.begin(), end = source.end();
83
84         for(;;)
85         {
86             read_past(it, end, "<");
87             if (it == end) break;
88
89             if (read(it, end, "!--quickbook-escape-prefix-->"))
90             {
91                 read_past(it, end, "<!--quickbook-escape-postfix-->");
92                 continue;
93             }
94
95             switch(*it)
96             {
97             case '?':
98                 ++it;
99                 read_past(it, end, "?>");
100                 break;
101
102             case '!':
103                 if (read(it, end, "!--"))
104                     read_past(it, end, "-->");
105                 else
106                     read_past(it, end, ">");
107                 break;
108
109             default:
110                 if ((*it >= 'a' && *it <= 'z') ||
111                         (*it >= 'A' && *it <= 'Z') ||
112                         *it == '_' || *it == ':')
113                 {
114                     read_to_one_of(it, end, " \t\n\r>");
115
116                     for (;;) {
117                         read_some_of(it, end, " \t\n\r");
118                         iterator name_start = it;
119                         read_to_one_of(it, end, "= \t\n\r>");
120                         if (it == end || *it == '>') break;
121                         boost::string_ref name(name_start, it - name_start);
122                         ++it;
123
124                         read_some_of(it, end, "= \t\n\r");
125                         if (it == end || (*it != '"' && *it != '\'')) break;
126
127                         char delim = *it;
128                         ++it;
129
130                         iterator value_start = it;
131
132                         it = std::find(it, end, delim);
133                         if (it == end) break;
134                         boost::string_ref value(value_start, it - value_start);
135                         ++it;
136
137                         if (boost::find(id_attributes, detail::to_s(name))
138                                 != id_attributes.end())
139                         {
140                             c.id_value(value);
141                         }
142                     }
143                 }
144                 else
145                 {
146                     read_past(it, end, ">");
147                 }
148             }
149         }
150
151         c.finish(source);
152     }
153 }