1 /*=============================================================================
2     Copyright (c) 2002 Juan Carlos Arevalo-Baeza
3     Copyright (c) 2002-2006 Hartmut Kaiser
4     Copyright (c) 2003 Giovanni Bajo
5     http://spirit.sourceforge.net/
6 
7   Distributed under the Boost Software License, Version 1.0. (See accompanying
8   file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 =============================================================================*/
10 #ifndef BOOST_SPIRIT_POSITION_ITERATOR_HPP
11 #define BOOST_SPIRIT_POSITION_ITERATOR_HPP
12 
13 #include <string>
14 #include <boost/config.hpp>
15 #include <boost/concept_check.hpp>
16 
17 #include <boost/spirit/home/classic/namespace.hpp>
18 #include <boost/spirit/home/classic/iterator/position_iterator_fwd.hpp>
19 
20 namespace boost { namespace spirit {
21 
22 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
23 
24 ///////////////////////////////////////////////////////////////////////////////
25 //
26 //  file_position_without_column
27 //
28 //  A structure to hold positional information. This includes the file,
29 //  and the line number
30 //
31 ///////////////////////////////////////////////////////////////////////////////
32 template <typename String>
33 struct file_position_without_column_base {
34     String file;
35     int line;
36 
file_position_without_column_baseboost::spirit::file_position_without_column_base37     file_position_without_column_base(String const& file_ = String(),
38                   int line_ = 1):
39         file    (file_),
40         line    (line_)
41     {}
42 
operator ==boost::spirit::file_position_without_column_base43     bool operator==(const file_position_without_column_base& fp) const
44     { return line == fp.line && file == fp.file; }
45 };
46 
47 ///////////////////////////////////////////////////////////////////////////////
48 //
49 //  file_position
50 //
51 //  This structure holds complete file position, including file name,
52 //  line and column number
53 //
54 ///////////////////////////////////////////////////////////////////////////////
55 template <typename String>
56 struct file_position_base : public file_position_without_column_base<String> {
57     int column;
58 
file_position_baseboost::spirit::file_position_base59     file_position_base(String const& file_ = String(),
60                        int line_ = 1, int column_ = 1):
61         file_position_without_column_base<String> (file_, line_),
62         column                       (column_)
63     {}
64 
operator ==boost::spirit::file_position_base65     bool operator==(const file_position_base& fp) const
66     { return column == fp.column && this->line == fp.line && this->file == fp.file; }
67 };
68 
69 ///////////////////////////////////////////////////////////////////////////////
70 //
71 //  position_policy<>
72 //
73 //  This template is the policy to handle the file position. It is specialized
74 //  on the position type. Providing a custom file_position also requires
75 //  providing a specialization of this class.
76 //
77 //  Policy interface:
78 //
79 //    Default constructor of the custom position class must be accessible.
80 //    set_tab_chars(unsigned int chars) - Set the tabstop width
81 //    next_char(PositionT& pos)  - Notify that a new character has been
82 //      processed
83 //    tabulation(PositionT& pos) - Notify that a tab character has been
84 //      processed
85 //    next_line(PositionT& pos)  - Notify that a new line delimiter has
86 //      been reached.
87 //
88 ///////////////////////////////////////////////////////////////////////////////
89 template <typename PositionT> class position_policy;
90 
91 ///////////////////////////////////////////////////////////////////////////////
92 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
93 
94 }} /* namespace BOOST_SPIRIT_CLASSIC_NS */
95 
96 
97 // This must be included here for full compatibility with old MSVC
98 #include <boost/spirit/home/classic/iterator/impl/position_iterator.ipp>
99 
100 ///////////////////////////////////////////////////////////////////////////////
101 namespace boost { namespace spirit {
102 
103 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
104 
105 ///////////////////////////////////////////////////////////////////////////////
106 //
107 //  position_iterator
108 //
109 //  It wraps an iterator, and keeps track of the current position in the input,
110 //  as it gets incremented.
111 //
112 //  The wrapped iterator must be at least a Forward iterator. The position
113 //  iterator itself will always be a non-mutable Forward iterator.
114 //
115 //  In order to have begin/end iterators constructed, the end iterator must be
116 //  empty constructed. Similar to what happens with stream iterators. The begin
117 //  iterator must be constructed from both, the begin and end iterators of the
118 //  wrapped iterator type. This is necessary to implement the lookahead of
119 //  characters necessary to parse CRLF sequences.
120 //
121 //  In order to extract the current positional data from the iterator, you may
122 //  use the get_position member function.
123 //
124 //  You can also use the set_position member function to reset the current
125 //  position to something new.
126 //
127 //  The structure that holds the current position can be customized through a
128 //  template parameter, and the class position_policy must be specialized
129 //  on the new type to define how to handle it. Currently, it's possible
130 //  to choose between the file_position and file_position_without_column
131 //  (which saves some overhead if managing current column is not required).
132 //
133 ///////////////////////////////////////////////////////////////////////////////
134 
135 #if !defined(BOOST_ITERATOR_ADAPTORS_VERSION) || \
136      BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200
137 #error "Please use at least Boost V1.31.0 while compiling the position_iterator class!"
138 #else // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200
139 
140 ///////////////////////////////////////////////////////////////////////////////
141 //
142 //  Uses the newer iterator_adaptor version (should be released with
143 //  Boost V1.31.0)
144 //
145 ///////////////////////////////////////////////////////////////////////////////
146 template <
147     typename ForwardIteratorT,
148     typename PositionT,
149     typename SelfT
150 >
151 class position_iterator
152 :   public iterator_::impl::position_iterator_base_generator<
153         SelfT,
154         ForwardIteratorT,
155         PositionT
156     >::type,
157     public position_policy<PositionT>
158 {
159 private:
160 
161     typedef position_policy<PositionT> position_policy_t;
162     typedef typename iterator_::impl::position_iterator_base_generator<
163             SelfT,
164             ForwardIteratorT,
165             PositionT
166         >::type base_t;
167     typedef typename iterator_::impl::position_iterator_base_generator<
168             SelfT,
169             ForwardIteratorT,
170             PositionT
171         >::main_iter_t main_iter_t;
172 
173 public:
174 
175     typedef PositionT position_t;
176 
177     position_iterator()
178     :   _isend(true)
179     {}
180 
181     position_iterator(
182         const ForwardIteratorT& begin,
183         const ForwardIteratorT& end)
184     :   base_t(begin), _end(end), _pos(PositionT()), _isend(begin == end)
185     {}
186 
187     template <typename FileNameT>
188     position_iterator(
189         const ForwardIteratorT& begin,
190         const ForwardIteratorT& end,
191         FileNameT fileName)
192     :   base_t(begin), _end(end), _pos(PositionT(fileName)),
193         _isend(begin == end)
194     {}
195 
196     template <typename FileNameT, typename LineT>
197     position_iterator(
198         const ForwardIteratorT& begin,
199         const ForwardIteratorT& end,
200         FileNameT fileName, LineT line)
201     :   base_t(begin), _end(end), _pos(PositionT(fileName, line)),
202         _isend(begin == end)
203     {}
204 
205     template <typename FileNameT, typename LineT, typename ColumnT>
206     position_iterator(
207         const ForwardIteratorT& begin,
208         const ForwardIteratorT& end,
209         FileNameT fileName, LineT line, ColumnT column)
210     :   base_t(begin), _end(end), _pos(PositionT(fileName, line, column)),
211         _isend(begin == end)
212     {}
213 
214     position_iterator(
215         const ForwardIteratorT& begin,
216         const ForwardIteratorT& end,
217         const PositionT& pos)
218     :   base_t(begin), _end(end), _pos(pos), _isend(begin == end)
219     {}
220 
221     position_iterator(const position_iterator& iter)
222     :   base_t(iter.base()), position_policy_t(iter),
223         _end(iter._end), _pos(iter._pos), _isend(iter._isend)
224     {}
225 
226     position_iterator& operator=(const position_iterator& iter)
227     {
228         base_t::operator=(iter);
229         position_policy_t::operator=(iter);
230         _end = iter._end;
231         _pos = iter._pos;
232         _isend = iter._isend;
233         return *this;
234     }
235 
236     void set_position(PositionT const& newpos) { _pos = newpos; }
237     PositionT& get_position() { return _pos; }
238     PositionT const& get_position() const { return _pos; }
239 
240     void set_tabchars(unsigned int chars)
241     {
242         // This function (which comes from the position_policy) has a
243         //  different name on purpose, to avoid messing with using
244         //  declarations or qualified calls to access the base template
245         //  function, which might break some compilers.
246         this->position_policy_t::set_tab_chars(chars);
247     }
248 
249 private:
250     friend class boost::iterator_core_access;
251 
252     void increment()
253     {
254         typename base_t::reference val = *(this->base());
255         if (val == '\n') {
256             ++this->base_reference();
257             this->next_line(_pos);
258             static_cast<main_iter_t &>(*this).newline();
259         }
260         else if ( val == '\r') {
261             ++this->base_reference();
262             if (this->base_reference() == _end || *(this->base()) != '\n')
263             {
264                 this->next_line(_pos);
265                 static_cast<main_iter_t &>(*this).newline();
266             }
267         }
268         else if (val == '\t') {
269             this->tabulation(_pos);
270             ++this->base_reference();
271         }
272         else {
273             this->next_char(_pos);
274             ++this->base_reference();
275         }
276 
277         // The iterator is at the end only if it's the same
278         //  of the
279         _isend = (this->base_reference() == _end);
280     }
281 
282     template <
283         typename OtherDerivedT, typename OtherIteratorT,
284         typename V, typename C, typename R, typename D
285     >
286     bool equal(iterator_adaptor<OtherDerivedT, OtherIteratorT, V, C, R, D>
287         const &x) const
288     {
289         OtherDerivedT const &rhs = static_cast<OtherDerivedT const &>(x);
290         bool x_is_end = rhs._isend;
291 
292         return (_isend == x_is_end) && (_isend || this->base() == rhs.base());
293     }
294 
295 protected:
296 
297     void newline(void)
298     {}
299 
300     ForwardIteratorT _end;
301     PositionT _pos;
302     bool _isend;
303 };
304 
305 #endif // BOOST_ITERATOR_ADAPTORS_VERSION < 0x0200
306 
307 ///////////////////////////////////////////////////////////////////////////////
308 //
309 //  position_iterator2
310 //
311 //  Equivalent to position_iterator, but it is able to extract the current
312 //  line into a string. This is very handy for error reports.
313 //
314 //  Notice that the footprint of this class is higher than position_iterator,
315 //  (how much depends on how bulky the underlying iterator is), so it should
316 //  be used only if necessary.
317 //
318 ///////////////////////////////////////////////////////////////////////////////
319 
320 template
321 <
322     typename ForwardIteratorT,
323     typename PositionT
324 >
325 class position_iterator2
326     : public position_iterator
327     <
328         ForwardIteratorT,
329         PositionT,
330         position_iterator2<ForwardIteratorT, PositionT>
331     >
332 {
333     typedef position_iterator
334     <
335         ForwardIteratorT,
336         PositionT,
337         position_iterator2<ForwardIteratorT, PositionT> // JDG 4-15-03
338     >  base_t;
339 
340 public:
341     typedef typename base_t::value_type value_type;
342     typedef PositionT position_t;
343 
position_iterator2()344     position_iterator2()
345     {}
346 
position_iterator2(const ForwardIteratorT & begin,const ForwardIteratorT & end)347     position_iterator2(
348         const ForwardIteratorT& begin,
349         const ForwardIteratorT& end):
350         base_t(begin, end),
351         _startline(begin)
352     {}
353 
354     template <typename FileNameT>
position_iterator2(const ForwardIteratorT & begin,const ForwardIteratorT & end,FileNameT file)355     position_iterator2(
356         const ForwardIteratorT& begin,
357         const ForwardIteratorT& end,
358         FileNameT file):
359         base_t(begin, end, file),
360         _startline(begin)
361     {}
362 
363     template <typename FileNameT, typename LineT>
position_iterator2(const ForwardIteratorT & begin,const ForwardIteratorT & end,FileNameT file,LineT line)364     position_iterator2(
365         const ForwardIteratorT& begin,
366         const ForwardIteratorT& end,
367         FileNameT file, LineT line):
368         base_t(begin, end, file, line),
369         _startline(begin)
370     {}
371 
372     template <typename FileNameT, typename LineT, typename ColumnT>
position_iterator2(const ForwardIteratorT & begin,const ForwardIteratorT & end,FileNameT file,LineT line,ColumnT column)373     position_iterator2(
374         const ForwardIteratorT& begin,
375         const ForwardIteratorT& end,
376         FileNameT file, LineT line, ColumnT column):
377         base_t(begin, end, file, line, column),
378         _startline(begin)
379     {}
380 
position_iterator2(const ForwardIteratorT & begin,const ForwardIteratorT & end,const PositionT & pos)381     position_iterator2(
382         const ForwardIteratorT& begin,
383         const ForwardIteratorT& end,
384         const PositionT& pos):
385         base_t(begin, end, pos),
386         _startline(begin)
387     {}
388 
position_iterator2(const position_iterator2 & iter)389     position_iterator2(const position_iterator2& iter)
390         : base_t(iter), _startline(iter._startline)
391     {}
392 
operator =(const position_iterator2 & iter)393     position_iterator2& operator=(const position_iterator2& iter)
394     {
395         base_t::operator=(iter);
396         _startline = iter._startline;
397         return *this;
398     }
399 
get_currentline_begin(void) const400     ForwardIteratorT get_currentline_begin(void) const
401     { return _startline; }
402 
get_currentline_end(void) const403     ForwardIteratorT get_currentline_end(void) const
404     { return get_endline(); }
405 
get_currentline(void) const406     std::basic_string<value_type> get_currentline(void) const
407     {
408         return std::basic_string<value_type>
409             (get_currentline_begin(), get_currentline_end());
410     }
411 
412 protected:
413     ForwardIteratorT _startline;
414 
415     friend class position_iterator<ForwardIteratorT, PositionT,
416         position_iterator2<ForwardIteratorT, PositionT> >;
417 
get_endline() const418     ForwardIteratorT get_endline() const
419     {
420         ForwardIteratorT endline = _startline;
421         while (endline != this->_end && *endline != '\r' && *endline != '\n')
422         {
423             ++endline;
424         }
425         return endline;
426     }
427 
newline(void)428     void newline(void)
429     { _startline = this->base(); }
430 };
431 
432 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
433 
434 }} // namespace BOOST_SPIRIT_CLASSIC_NS
435 
436 #endif
437