Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 1998-2009 John Maddock
4 : * Copyright 2008 Eric Niebler.
5 : *
6 : * Use, modification and distribution are subject to the
7 : * Boost Software License, Version 1.0. (See accompanying file
8 : * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 : *
10 : */
11 :
12 : /*
13 : * LOCATION: see http://www.boost.org for most recent version.
14 : * FILE regex_format.hpp
15 : * VERSION see <boost/version.hpp>
16 : * DESCRIPTION: Provides formatting output routines for search and replace
17 : * operations. Note this is an internal header file included
18 : * by regex.hpp, do not include on its own.
19 : */
20 :
21 : #ifndef BOOST_REGEX_FORMAT_HPP
22 : #define BOOST_REGEX_FORMAT_HPP
23 :
24 : #include <boost/type_traits/is_pointer.hpp>
25 : #include <boost/type_traits/is_function.hpp>
26 : #include <boost/type_traits/is_class.hpp>
27 : #include <boost/type_traits/is_same.hpp>
28 : #include <boost/type_traits/is_convertible.hpp>
29 : #include <boost/type_traits/remove_pointer.hpp>
30 : #include <boost/type_traits/remove_cv.hpp>
31 : #include <boost/mpl/if.hpp>
32 : #include <boost/mpl/and.hpp>
33 : #include <boost/mpl/not.hpp>
34 : #ifndef BOOST_NO_SFINAE
35 : #include <boost/mpl/has_xxx.hpp>
36 : #endif
37 : #include <boost/ref.hpp>
38 :
39 : namespace boost{
40 :
41 : #ifdef BOOST_MSVC
42 : #pragma warning(push)
43 : #pragma warning(disable: 4103)
44 : #endif
45 : #ifdef BOOST_HAS_ABI_HEADERS
46 : # include BOOST_ABI_PREFIX
47 : #endif
48 : #ifdef BOOST_MSVC
49 : #pragma warning(pop)
50 : #endif
51 :
52 : //
53 : // Forward declaration:
54 : //
55 : template <class BidiIterator, class Allocator = BOOST_DEDUCED_TYPENAME std::vector<sub_match<BidiIterator> >::allocator_type >
56 : class match_results;
57 :
58 : namespace BOOST_REGEX_DETAIL_NS{
59 :
60 : //
61 : // struct trivial_format_traits:
62 : // defines minimum localisation support for formatting
63 : // in the case that the actual regex traits is unavailable.
64 : //
65 : template <class charT>
66 : struct trivial_format_traits
67 : {
68 : typedef charT char_type;
69 :
70 : static std::ptrdiff_t length(const charT* p)
71 : {
72 : return global_length(p);
73 : }
74 : static charT tolower(charT c)
75 : {
76 : return ::boost::BOOST_REGEX_DETAIL_NS::global_lower(c);
77 : }
78 : static charT toupper(charT c)
79 : {
80 : return ::boost::BOOST_REGEX_DETAIL_NS::global_upper(c);
81 : }
82 : static int value(const charT c, int radix)
83 : {
84 : int result = global_value(c);
85 : return result >= radix ? -1 : result;
86 : }
87 : int toi(const charT*& p1, const charT* p2, int radix)const
88 : {
89 : return (int)global_toi(p1, p2, radix, *this);
90 : }
91 : };
92 :
93 : template <class OutputIterator, class Results, class traits, class ForwardIter>
94 : class basic_regex_formatter
95 : {
96 : public:
97 : typedef typename traits::char_type char_type;
98 0 : basic_regex_formatter(OutputIterator o, const Results& r, const traits& t)
99 0 : : m_traits(t), m_results(r), m_out(o), m_position(), m_end(), m_flags(), m_state(output_copy), m_restore_state(output_copy), m_have_conditional(false) {}
100 : OutputIterator format(ForwardIter p1, ForwardIter p2, match_flag_type f);
101 : OutputIterator format(ForwardIter p1, match_flag_type f)
102 : {
103 : return format(p1, p1 + m_traits.length(p1), f);
104 : }
105 : private:
106 : typedef typename Results::value_type sub_match_type;
107 : enum output_state
108 : {
109 : output_copy,
110 : output_next_lower,
111 : output_next_upper,
112 : output_lower,
113 : output_upper,
114 : output_none
115 : };
116 :
117 : void put(char_type c);
118 : void put(const sub_match_type& sub);
119 : void format_all();
120 : void format_perl();
121 : void format_escape();
122 : void format_conditional();
123 : void format_until_scope_end();
124 : bool handle_perl_verb(bool have_brace);
125 :
126 : inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const mpl::false_&)
127 : {
128 : std::vector<char_type> v(i, j);
129 : return (i != j) ? this->m_results.named_subexpression(&v[0], &v[0] + v.size())
130 : : this->m_results.named_subexpression(static_cast<const char_type*>(0), static_cast<const char_type*>(0));
131 : }
132 0 : inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const mpl::true_&)
133 : {
134 0 : return this->m_results.named_subexpression(i, j);
135 : }
136 0 : inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j)
137 : {
138 : typedef typename boost::is_convertible<ForwardIter, const char_type*>::type tag_type;
139 0 : return get_named_sub(i, j, tag_type());
140 : }
141 : inline int get_named_sub_index(ForwardIter i, ForwardIter j, const mpl::false_&)
142 : {
143 : std::vector<char_type> v(i, j);
144 : return (i != j) ? this->m_results.named_subexpression_index(&v[0], &v[0] + v.size())
145 : : this->m_results.named_subexpression_index(static_cast<const char_type*>(0), static_cast<const char_type*>(0));
146 : }
147 0 : inline int get_named_sub_index(ForwardIter i, ForwardIter j, const mpl::true_&)
148 : {
149 0 : return this->m_results.named_subexpression_index(i, j);
150 : }
151 0 : inline int get_named_sub_index(ForwardIter i, ForwardIter j)
152 : {
153 : typedef typename boost::is_convertible<ForwardIter, const char_type*>::type tag_type;
154 0 : return get_named_sub_index(i, j, tag_type());
155 : }
156 : #ifdef BOOST_MSVC
157 : // msvc-8.0 issues a spurious warning on the call to std::advance here:
158 : #pragma warning(push)
159 : #pragma warning(disable:4244)
160 : #endif
161 0 : inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::false_&)
162 : {
163 0 : if(i != j)
164 : {
165 0 : std::vector<char_type> v(i, j);
166 0 : const char_type* start = &v[0];
167 0 : const char_type* pos = start;
168 0 : int r = (int)m_traits.toi(pos, &v[0] + v.size(), base);
169 0 : std::advance(i, pos - start);
170 0 : return r;
171 : }
172 : return -1;
173 : }
174 : #ifdef BOOST_MSVC
175 : #pragma warning(pop)
176 : #endif
177 : inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::true_&)
178 : {
179 : return m_traits.toi(i, j, base);
180 : }
181 0 : inline int toi(ForwardIter& i, ForwardIter j, int base)
182 : {
183 : #if defined(_MSC_VER) && defined(__INTEL_COMPILER) && ((__INTEL_COMPILER == 9999) || (__INTEL_COMPILER == 1210))
184 : // Workaround for Intel support issue #656654.
185 : // See also https://svn.boost.org/trac/boost/ticket/6359
186 : return toi(i, j, base, mpl::false_());
187 : #else
188 : typedef typename boost::is_convertible<ForwardIter, const char_type*&>::type tag_type;
189 0 : return toi(i, j, base, tag_type());
190 : #endif
191 : }
192 :
193 : const traits& m_traits; // the traits class for localised formatting operations
194 : const Results& m_results; // the match_results being used.
195 : OutputIterator m_out; // where to send output.
196 : ForwardIter m_position; // format string, current position
197 : ForwardIter m_end; // format string end
198 : match_flag_type m_flags; // format flags to use
199 : output_state m_state; // what to do with the next character
200 : output_state m_restore_state; // what state to restore to.
201 : bool m_have_conditional; // we are parsing a conditional
202 : private:
203 : basic_regex_formatter(const basic_regex_formatter&);
204 : basic_regex_formatter& operator=(const basic_regex_formatter&);
205 : };
206 :
207 : template <class OutputIterator, class Results, class traits, class ForwardIter>
208 0 : OutputIterator basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format(ForwardIter p1, ForwardIter p2, match_flag_type f)
209 : {
210 0 : m_position = p1;
211 0 : m_end = p2;
212 0 : m_flags = f;
213 0 : format_all();
214 0 : return m_out;
215 : }
216 :
217 : template <class OutputIterator, class Results, class traits, class ForwardIter>
218 0 : void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_all()
219 : {
220 : // over and over:
221 0 : while(m_position != m_end)
222 : {
223 0 : switch(*m_position)
224 : {
225 0 : case '&':
226 0 : if(m_flags & ::boost::regex_constants::format_sed)
227 : {
228 0 : ++m_position;
229 0 : put(m_results[0]);
230 : break;
231 : }
232 0 : put(*m_position++);
233 0 : break;
234 0 : case '\\':
235 0 : format_escape();
236 0 : break;
237 0 : case '(':
238 0 : if(m_flags & boost::regex_constants::format_all)
239 : {
240 0 : ++m_position;
241 0 : bool have_conditional = m_have_conditional;
242 0 : m_have_conditional = false;
243 0 : format_until_scope_end();
244 0 : m_have_conditional = have_conditional;
245 0 : if(m_position == m_end)
246 : return;
247 0 : BOOST_ASSERT(*m_position == static_cast<char_type>(')'));
248 0 : ++m_position; // skip the closing ')'
249 0 : break;
250 : }
251 0 : put(*m_position);
252 0 : ++m_position;
253 0 : break;
254 0 : case ')':
255 0 : if(m_flags & boost::regex_constants::format_all)
256 : {
257 : return;
258 : }
259 0 : put(*m_position);
260 0 : ++m_position;
261 0 : break;
262 0 : case ':':
263 0 : if((m_flags & boost::regex_constants::format_all) && m_have_conditional)
264 : {
265 : return;
266 : }
267 0 : put(*m_position);
268 0 : ++m_position;
269 0 : break;
270 0 : case '?':
271 0 : if(m_flags & boost::regex_constants::format_all)
272 : {
273 0 : ++m_position;
274 0 : format_conditional();
275 0 : break;
276 : }
277 0 : put(*m_position);
278 0 : ++m_position;
279 0 : break;
280 0 : case '$':
281 0 : if((m_flags & format_sed) == 0)
282 : {
283 0 : format_perl();
284 0 : break;
285 : }
286 : // not a special character:
287 : BOOST_FALLTHROUGH;
288 : default:
289 0 : put(*m_position);
290 0 : ++m_position;
291 0 : break;
292 : }
293 : }
294 : }
295 :
296 : template <class OutputIterator, class Results, class traits, class ForwardIter>
297 0 : void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_perl()
298 : {
299 : //
300 : // On entry *m_position points to a '$' character
301 : // output the information that goes with it:
302 : //
303 0 : BOOST_ASSERT(*m_position == '$');
304 : //
305 : // see if this is a trailing '$':
306 : //
307 0 : if(++m_position == m_end)
308 : {
309 0 : --m_position;
310 0 : put(*m_position);
311 0 : ++m_position;
312 0 : return;
313 : }
314 : //
315 : // OK find out what kind it is:
316 : //
317 0 : bool have_brace = false;
318 0 : ForwardIter save_position = m_position;
319 0 : switch(*m_position)
320 : {
321 0 : case '&':
322 0 : ++m_position;
323 0 : put(this->m_results[0]);
324 : break;
325 0 : case '`':
326 0 : ++m_position;
327 0 : put(this->m_results.prefix());
328 : break;
329 0 : case '\'':
330 0 : ++m_position;
331 0 : put(this->m_results.suffix());
332 : break;
333 0 : case '$':
334 0 : put(*m_position++);
335 0 : break;
336 0 : case '+':
337 0 : if((++m_position != m_end) && (*m_position == '{'))
338 : {
339 0 : ForwardIter base = ++m_position;
340 0 : while((m_position != m_end) && (*m_position != '}')) ++m_position;
341 0 : if(m_position != m_end)
342 : {
343 : // Named sub-expression:
344 0 : put(get_named_sub(base, m_position));
345 0 : ++m_position;
346 0 : break;
347 : }
348 : else
349 : {
350 0 : m_position = --base;
351 : }
352 : }
353 0 : put((this->m_results)[this->m_results.size() > 1 ? static_cast<int>(this->m_results.size() - 1) : 1]);
354 : break;
355 0 : case '{':
356 0 : have_brace = true;
357 0 : ++m_position;
358 : BOOST_FALLTHROUGH;
359 0 : default:
360 : // see if we have a number:
361 : {
362 0 : std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
363 : //len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
364 0 : int v = this->toi(m_position, m_position + len, 10);
365 0 : if((v < 0) || (have_brace && ((m_position == m_end) || (*m_position != '}'))))
366 : {
367 : // Look for a Perl-5.10 verb:
368 0 : if(!handle_perl_verb(have_brace))
369 : {
370 : // leave the $ as is, and carry on:
371 0 : m_position = --save_position;
372 0 : put(*m_position);
373 0 : ++m_position;
374 : }
375 : break;
376 : }
377 : // otherwise output sub v:
378 0 : put(this->m_results[v]);
379 0 : if(have_brace)
380 0 : ++m_position;
381 : }
382 : }
383 : }
384 :
385 : template <class OutputIterator, class Results, class traits, class ForwardIter>
386 0 : bool basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::handle_perl_verb(bool have_brace)
387 : {
388 : //
389 : // We may have a capitalised string containing a Perl action:
390 : //
391 : static const char_type MATCH[] = { 'M', 'A', 'T', 'C', 'H' };
392 : static const char_type PREMATCH[] = { 'P', 'R', 'E', 'M', 'A', 'T', 'C', 'H' };
393 : static const char_type POSTMATCH[] = { 'P', 'O', 'S', 'T', 'M', 'A', 'T', 'C', 'H' };
394 : static const char_type LAST_PAREN_MATCH[] = { 'L', 'A', 'S', 'T', '_', 'P', 'A', 'R', 'E', 'N', '_', 'M', 'A', 'T', 'C', 'H' };
395 : static const char_type LAST_SUBMATCH_RESULT[] = { 'L', 'A', 'S', 'T', '_', 'S', 'U', 'B', 'M', 'A', 'T', 'C', 'H', '_', 'R', 'E', 'S', 'U', 'L', 'T' };
396 : static const char_type LAST_SUBMATCH_RESULT_ALT[] = { '^', 'N' };
397 :
398 0 : if(m_position == m_end)
399 : return false;
400 0 : if(have_brace && (*m_position == '^'))
401 0 : ++m_position;
402 :
403 0 : std::ptrdiff_t max_len = m_end - m_position;
404 :
405 0 : if((max_len >= 5) && std::equal(m_position, m_position + 5, MATCH))
406 : {
407 0 : m_position += 5;
408 0 : if(have_brace)
409 : {
410 0 : if((m_position != m_end) && (*m_position == '}'))
411 0 : ++m_position;
412 : else
413 : {
414 0 : m_position -= 5;
415 0 : return false;
416 : }
417 : }
418 0 : put(this->m_results[0]);
419 : return true;
420 : }
421 0 : if((max_len >= 8) && std::equal(m_position, m_position + 8, PREMATCH))
422 : {
423 0 : m_position += 8;
424 0 : if(have_brace)
425 : {
426 0 : if((m_position != m_end) && (*m_position == '}'))
427 0 : ++m_position;
428 : else
429 : {
430 0 : m_position -= 8;
431 0 : return false;
432 : }
433 : }
434 0 : put(this->m_results.prefix());
435 : return true;
436 : }
437 0 : if((max_len >= 9) && std::equal(m_position, m_position + 9, POSTMATCH))
438 : {
439 0 : m_position += 9;
440 0 : if(have_brace)
441 : {
442 0 : if((m_position != m_end) && (*m_position == '}'))
443 0 : ++m_position;
444 : else
445 : {
446 0 : m_position -= 9;
447 0 : return false;
448 : }
449 : }
450 0 : put(this->m_results.suffix());
451 : return true;
452 : }
453 0 : if((max_len >= 16) && std::equal(m_position, m_position + 16, LAST_PAREN_MATCH))
454 : {
455 0 : m_position += 16;
456 0 : if(have_brace)
457 : {
458 0 : if((m_position != m_end) && (*m_position == '}'))
459 0 : ++m_position;
460 : else
461 : {
462 0 : m_position -= 16;
463 0 : return false;
464 : }
465 : }
466 0 : put((this->m_results)[this->m_results.size() > 1 ? static_cast<int>(this->m_results.size() - 1) : 1]);
467 : return true;
468 : }
469 0 : if((max_len >= 20) && std::equal(m_position, m_position + 20, LAST_SUBMATCH_RESULT))
470 : {
471 0 : m_position += 20;
472 0 : if(have_brace)
473 : {
474 0 : if((m_position != m_end) && (*m_position == '}'))
475 0 : ++m_position;
476 : else
477 : {
478 0 : m_position -= 20;
479 0 : return false;
480 : }
481 : }
482 0 : put(this->m_results.get_last_closed_paren());
483 : return true;
484 : }
485 0 : if((max_len >= 2) && std::equal(m_position, m_position + 2, LAST_SUBMATCH_RESULT_ALT))
486 : {
487 0 : m_position += 2;
488 0 : if(have_brace)
489 : {
490 0 : if((m_position != m_end) && (*m_position == '}'))
491 0 : ++m_position;
492 : else
493 : {
494 0 : m_position -= 2;
495 0 : return false;
496 : }
497 : }
498 0 : put(this->m_results.get_last_closed_paren());
499 : return true;
500 : }
501 : return false;
502 : }
503 :
504 : template <class OutputIterator, class Results, class traits, class ForwardIter>
505 0 : void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_escape()
506 : {
507 : // skip the escape and check for trailing escape:
508 0 : if(++m_position == m_end)
509 : {
510 0 : put(static_cast<char_type>('\\'));
511 0 : return;
512 : }
513 : // now switch on the escape type:
514 0 : switch(*m_position)
515 : {
516 0 : case 'a':
517 0 : put(static_cast<char_type>('\a'));
518 0 : ++m_position;
519 0 : break;
520 0 : case 'f':
521 0 : put(static_cast<char_type>('\f'));
522 0 : ++m_position;
523 0 : break;
524 0 : case 'n':
525 0 : put(static_cast<char_type>('\n'));
526 0 : ++m_position;
527 0 : break;
528 0 : case 'r':
529 0 : put(static_cast<char_type>('\r'));
530 0 : ++m_position;
531 0 : break;
532 0 : case 't':
533 0 : put(static_cast<char_type>('\t'));
534 0 : ++m_position;
535 0 : break;
536 0 : case 'v':
537 0 : put(static_cast<char_type>('\v'));
538 0 : ++m_position;
539 0 : break;
540 0 : case 'x':
541 0 : if(++m_position == m_end)
542 : {
543 0 : put(static_cast<char_type>('x'));
544 0 : return;
545 : }
546 : // maybe have \x{ddd}
547 0 : if(*m_position == static_cast<char_type>('{'))
548 : {
549 0 : ++m_position;
550 0 : int val = this->toi(m_position, m_end, 16);
551 0 : if(val < 0)
552 : {
553 : // invalid value treat everything as literals:
554 0 : put(static_cast<char_type>('x'));
555 0 : put(static_cast<char_type>('{'));
556 0 : return;
557 : }
558 0 : if((m_position == m_end) || (*m_position != static_cast<char_type>('}')))
559 : {
560 0 : --m_position;
561 0 : while(*m_position != static_cast<char_type>('\\'))
562 0 : --m_position;
563 0 : ++m_position;
564 0 : put(*m_position++);
565 0 : return;
566 : }
567 0 : ++m_position;
568 0 : put(static_cast<char_type>(val));
569 0 : return;
570 : }
571 : else
572 : {
573 0 : std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
574 0 : len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
575 0 : int val = this->toi(m_position, m_position + len, 16);
576 0 : if(val < 0)
577 : {
578 0 : --m_position;
579 0 : put(*m_position++);
580 0 : return;
581 : }
582 0 : put(static_cast<char_type>(val));
583 : }
584 0 : break;
585 0 : case 'c':
586 0 : if(++m_position == m_end)
587 : {
588 : --m_position;
589 0 : put(*m_position++);
590 0 : return;
591 : }
592 0 : put(static_cast<char_type>(*m_position++ % 32));
593 : break;
594 0 : case 'e':
595 0 : put(static_cast<char_type>(27));
596 0 : ++m_position;
597 0 : break;
598 0 : default:
599 : // see if we have a perl specific escape:
600 0 : if((m_flags & boost::regex_constants::format_sed) == 0)
601 : {
602 0 : bool breakout = false;
603 : switch(*m_position)
604 : {
605 0 : case 'l':
606 0 : ++m_position;
607 0 : m_restore_state = m_state;
608 0 : m_state = output_next_lower;
609 : breakout = true;
610 : break;
611 0 : case 'L':
612 0 : ++m_position;
613 0 : m_state = output_lower;
614 : breakout = true;
615 : break;
616 0 : case 'u':
617 0 : ++m_position;
618 0 : m_restore_state = m_state;
619 0 : m_state = output_next_upper;
620 : breakout = true;
621 : break;
622 0 : case 'U':
623 0 : ++m_position;
624 0 : m_state = output_upper;
625 : breakout = true;
626 : break;
627 0 : case 'E':
628 0 : ++m_position;
629 0 : m_state = output_copy;
630 : breakout = true;
631 : break;
632 : }
633 : if(breakout)
634 : break;
635 : }
636 : // see if we have a \n sed style backreference:
637 0 : std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
638 0 : len = (std::min)(static_cast<std::ptrdiff_t>(1), len);
639 0 : int v = this->toi(m_position, m_position+len, 10);
640 0 : if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed)))
641 : {
642 0 : put(m_results[v]);
643 : break;
644 : }
645 0 : else if(v == 0)
646 : {
647 : // octal ecape sequence:
648 0 : --m_position;
649 0 : len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
650 0 : len = (std::min)(static_cast<std::ptrdiff_t>(4), len);
651 0 : v = this->toi(m_position, m_position + len, 8);
652 0 : BOOST_ASSERT(v >= 0);
653 0 : put(static_cast<char_type>(v));
654 : break;
655 : }
656 : // Otherwise output the character "as is":
657 0 : put(*m_position++);
658 : break;
659 : }
660 : }
661 :
662 : template <class OutputIterator, class Results, class traits, class ForwardIter>
663 0 : void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_conditional()
664 : {
665 0 : if(m_position == m_end)
666 : {
667 : // oops trailing '?':
668 0 : put(static_cast<char_type>('?'));
669 0 : return;
670 : }
671 : int v;
672 0 : if(*m_position == '{')
673 : {
674 0 : ForwardIter base = m_position;
675 0 : ++m_position;
676 0 : v = this->toi(m_position, m_end, 10);
677 0 : if(v < 0)
678 : {
679 : // Try a named subexpression:
680 0 : while((m_position != m_end) && (*m_position != '}'))
681 0 : ++m_position;
682 0 : v = this->get_named_sub_index(base + 1, m_position);
683 : }
684 0 : if((v < 0) || (*m_position != '}'))
685 : {
686 0 : m_position = base;
687 : // oops trailing '?':
688 0 : put(static_cast<char_type>('?'));
689 0 : return;
690 : }
691 : // Skip trailing '}':
692 0 : ++m_position;
693 : }
694 : else
695 : {
696 0 : std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
697 0 : len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
698 0 : v = this->toi(m_position, m_position + len, 10);
699 : }
700 0 : if(v < 0)
701 : {
702 : // oops not a number:
703 0 : put(static_cast<char_type>('?'));
704 0 : return;
705 : }
706 :
707 : // output varies depending upon whether sub-expression v matched or not:
708 0 : if(m_results[v].matched)
709 : {
710 0 : m_have_conditional = true;
711 0 : format_all();
712 0 : m_have_conditional = false;
713 0 : if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
714 : {
715 : // skip the ':':
716 0 : ++m_position;
717 : // save output state, then turn it off:
718 0 : output_state saved_state = m_state;
719 0 : m_state = output_none;
720 : // format the rest of this scope:
721 0 : format_until_scope_end();
722 : // restore output state:
723 0 : m_state = saved_state;
724 : }
725 : }
726 : else
727 : {
728 : // save output state, then turn it off:
729 0 : output_state saved_state = m_state;
730 0 : m_state = output_none;
731 : // format until ':' or ')':
732 0 : m_have_conditional = true;
733 0 : format_all();
734 0 : m_have_conditional = false;
735 : // restore state:
736 0 : m_state = saved_state;
737 0 : if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
738 : {
739 : // skip the ':':
740 0 : ++m_position;
741 : // format the rest of this scope:
742 0 : format_until_scope_end();
743 : }
744 : }
745 : }
746 :
747 : template <class OutputIterator, class Results, class traits, class ForwardIter>
748 0 : void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_until_scope_end()
749 : {
750 : do
751 : {
752 0 : format_all();
753 0 : if((m_position == m_end) || (*m_position == static_cast<char_type>(')')))
754 : return;
755 0 : put(*m_position++);
756 0 : }while(m_position != m_end);
757 : }
758 :
759 : template <class OutputIterator, class Results, class traits, class ForwardIter>
760 0 : void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::put(char_type c)
761 : {
762 : // write a single character to output
763 : // according to which case translation mode we are in:
764 0 : switch(this->m_state)
765 : {
766 : case output_none:
767 : return;
768 0 : case output_next_lower:
769 0 : c = m_traits.tolower(c);
770 0 : this->m_state = m_restore_state;
771 0 : break;
772 0 : case output_next_upper:
773 0 : c = m_traits.toupper(c);
774 0 : this->m_state = m_restore_state;
775 0 : break;
776 0 : case output_lower:
777 0 : c = m_traits.tolower(c);
778 0 : break;
779 0 : case output_upper:
780 0 : c = m_traits.toupper(c);
781 0 : break;
782 : default:
783 : break;
784 : }
785 0 : *m_out = c;
786 0 : ++m_out;
787 : }
788 :
789 : template <class OutputIterator, class Results, class traits, class ForwardIter>
790 0 : void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::put(const sub_match_type& sub)
791 : {
792 : typedef typename sub_match_type::iterator iterator_type;
793 0 : iterator_type i = sub.first;
794 0 : while(i != sub.second)
795 : {
796 0 : put(*i);
797 0 : ++i;
798 : }
799 : }
800 :
801 : template <class S>
802 : class string_out_iterator
803 : {
804 : S* out;
805 : public:
806 : string_out_iterator(S& s) : out(&s) {}
807 : string_out_iterator& operator++() { return *this; }
808 : string_out_iterator& operator++(int) { return *this; }
809 : string_out_iterator& operator*() { return *this; }
810 : string_out_iterator& operator=(typename S::value_type v)
811 : {
812 : out->append(1, v);
813 : return *this;
814 : }
815 :
816 : typedef std::ptrdiff_t difference_type;
817 : typedef typename S::value_type value_type;
818 : typedef value_type* pointer;
819 : typedef value_type& reference;
820 : typedef std::output_iterator_tag iterator_category;
821 : };
822 :
823 : template <class OutputIterator, class Iterator, class Alloc, class ForwardIter, class traits>
824 0 : OutputIterator regex_format_imp(OutputIterator out,
825 : const match_results<Iterator, Alloc>& m,
826 : ForwardIter p1, ForwardIter p2,
827 : match_flag_type flags,
828 : const traits& t
829 : )
830 : {
831 0 : if(flags & regex_constants::format_literal)
832 : {
833 0 : return BOOST_REGEX_DETAIL_NS::copy(p1, p2, out);
834 : }
835 :
836 : BOOST_REGEX_DETAIL_NS::basic_regex_formatter<
837 : OutputIterator,
838 : match_results<Iterator, Alloc>,
839 0 : traits, ForwardIter> f(out, m, t);
840 0 : return f.format(p1, p2, flags);
841 : }
842 :
843 : #ifndef BOOST_NO_SFINAE
844 :
845 : BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator)
846 :
847 : struct any_type
848 : {
849 : template <class T>
850 : any_type(const T&);
851 : template <class T, class U>
852 : any_type(const T&, const U&);
853 : template <class T, class U, class V>
854 : any_type(const T&, const U&, const V&);
855 : };
856 : typedef char no_type;
857 : typedef char (&unary_type)[2];
858 : typedef char (&binary_type)[3];
859 : typedef char (&ternary_type)[4];
860 :
861 : no_type check_is_formatter(unary_type, binary_type, ternary_type);
862 : template<typename T>
863 : unary_type check_is_formatter(T const &, binary_type, ternary_type);
864 : template<typename T>
865 : binary_type check_is_formatter(unary_type, T const &, ternary_type);
866 : template<typename T, typename U>
867 : binary_type check_is_formatter(T const &, U const &, ternary_type);
868 : template<typename T>
869 : ternary_type check_is_formatter(unary_type, binary_type, T const &);
870 : template<typename T, typename U>
871 : ternary_type check_is_formatter(T const &, binary_type, U const &);
872 : template<typename T, typename U>
873 : ternary_type check_is_formatter(unary_type, T const &, U const &);
874 : template<typename T, typename U, typename V>
875 : ternary_type check_is_formatter(T const &, U const &, V const &);
876 :
877 : struct unary_binary_ternary
878 : {
879 : typedef unary_type (*unary_fun)(any_type);
880 : typedef binary_type (*binary_fun)(any_type, any_type);
881 : typedef ternary_type (*ternary_fun)(any_type, any_type, any_type);
882 : operator unary_fun();
883 : operator binary_fun();
884 : operator ternary_fun();
885 : };
886 :
887 : template<typename Formatter, bool IsFunction = boost::is_function<Formatter>::value>
888 : struct formatter_wrapper
889 : : Formatter
890 : , unary_binary_ternary
891 : {
892 : formatter_wrapper(){}
893 : };
894 :
895 : template<typename Formatter>
896 : struct formatter_wrapper<Formatter, true>
897 : : unary_binary_ternary
898 : {
899 : operator Formatter *();
900 : };
901 :
902 : template<typename Formatter>
903 : struct formatter_wrapper<Formatter *, false>
904 : : unary_binary_ternary
905 : {
906 : operator Formatter *();
907 : };
908 :
909 : template <class F, class M, class O>
910 : struct format_traits_imp
911 : {
912 : private:
913 : //
914 : // F must be a pointer, a function, or a class with a function call operator:
915 : //
916 : BOOST_STATIC_ASSERT((::boost::is_pointer<F>::value || ::boost::is_function<F>::value || ::boost::is_class<F>::value));
917 : static formatter_wrapper<typename unwrap_reference<F>::type> f;
918 : static M m;
919 : static O out;
920 : static boost::regex_constants::match_flag_type flags;
921 : public:
922 : BOOST_STATIC_CONSTANT(int, value = sizeof(check_is_formatter(f(m), f(m, out), f(m, out, flags))));
923 : };
924 :
925 : template <class F, class M, class O>
926 : struct format_traits
927 : {
928 : public:
929 : //
930 : // Type is mpl::int_<N> where N is one of:
931 : //
932 : // 0 : F is a pointer to a presumably null-terminated string.
933 : // 1 : F is a character-container such as a std::string.
934 : // 2 : F is a Unary Functor.
935 : // 3 : F is a Binary Functor.
936 : // 4 : F is a Ternary Functor.
937 : //
938 : typedef typename boost::mpl::if_<
939 : boost::mpl::and_<boost::is_pointer<F>, boost::mpl::not_<boost::is_function<typename boost::remove_pointer<F>::type> > >,
940 : boost::mpl::int_<0>,
941 : typename boost::mpl::if_<
942 : has_const_iterator<F>,
943 : boost::mpl::int_<1>,
944 : boost::mpl::int_<format_traits_imp<F, M, O>::value>
945 : >::type
946 : >::type type;
947 : //
948 : // This static assertion will fail if the functor passed does not accept
949 : // the same type of arguments passed.
950 : //
951 : BOOST_STATIC_ASSERT( boost::is_class<F>::value && !has_const_iterator<F>::value ? (type::value > 1) : true);
952 : };
953 :
954 : #else // BOOST_NO_SFINAE
955 :
956 : template <class F, class M, class O>
957 : struct format_traits
958 : {
959 : public:
960 : //
961 : // Type is mpl::int_<N> where N is one of:
962 : //
963 : // 0 : F is a pointer to a presumably null-terminated string.
964 : // 1 : F is a character-container such as a std::string.
965 : //
966 : // Other options such as F being a Functor are not supported without
967 : // SFINAE support.
968 : //
969 : typedef typename boost::mpl::if_<
970 : boost::is_pointer<F>,
971 : boost::mpl::int_<0>,
972 : boost::mpl::int_<1>
973 : >::type type;
974 : };
975 :
976 : #endif // BOOST_NO_SFINAE
977 :
978 : template <class Base, class Match>
979 : struct format_functor3
980 : {
981 : format_functor3(Base b) : func(b) {}
982 : template <class OutputIter>
983 : OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f)
984 : {
985 : return boost::unwrap_ref(func)(m, i, f);
986 : }
987 : template <class OutputIter, class Traits>
988 : OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
989 : {
990 : return (*this)(m, i, f);
991 : }
992 : private:
993 : Base func;
994 : format_functor3(const format_functor3&);
995 : format_functor3& operator=(const format_functor3&);
996 : };
997 :
998 : template <class Base, class Match>
999 : struct format_functor2
1000 : {
1001 : format_functor2(Base b) : func(b) {}
1002 : template <class OutputIter>
1003 : OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/)
1004 : {
1005 : return boost::unwrap_ref(func)(m, i);
1006 : }
1007 : template <class OutputIter, class Traits>
1008 : OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
1009 : {
1010 : return (*this)(m, i, f);
1011 : }
1012 : private:
1013 : Base func;
1014 : format_functor2(const format_functor2&);
1015 : format_functor2& operator=(const format_functor2&);
1016 : };
1017 :
1018 : template <class Base, class Match>
1019 : struct format_functor1
1020 : {
1021 : format_functor1(Base b) : func(b) {}
1022 :
1023 : template <class S, class OutputIter>
1024 : OutputIter do_format_string(const S& s, OutputIter i)
1025 : {
1026 : return BOOST_REGEX_DETAIL_NS::copy(s.begin(), s.end(), i);
1027 : }
1028 : template <class S, class OutputIter>
1029 : inline OutputIter do_format_string(const S* s, OutputIter i)
1030 : {
1031 : while(s && *s)
1032 : {
1033 : *i = *s;
1034 : ++i;
1035 : ++s;
1036 : }
1037 : return i;
1038 : }
1039 : template <class OutputIter>
1040 : OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/)
1041 : {
1042 : return do_format_string(boost::unwrap_ref(func)(m), i);
1043 : }
1044 : template <class OutputIter, class Traits>
1045 : OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
1046 : {
1047 : return (*this)(m, i, f);
1048 : }
1049 : private:
1050 : Base func;
1051 : format_functor1(const format_functor1&);
1052 : format_functor1& operator=(const format_functor1&);
1053 : };
1054 :
1055 : template <class charT, class Match, class Traits>
1056 : struct format_functor_c_string
1057 : {
1058 : format_functor_c_string(const charT* ps) : func(ps) {}
1059 :
1060 : template <class OutputIter>
1061 : OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits())
1062 : {
1063 : //typedef typename Match::char_type char_type;
1064 : const charT* end = func;
1065 : while(*end) ++end;
1066 : return regex_format_imp(i, m, func, end, f, t);
1067 : }
1068 : private:
1069 : const charT* func;
1070 : format_functor_c_string(const format_functor_c_string&);
1071 : format_functor_c_string& operator=(const format_functor_c_string&);
1072 : };
1073 :
1074 : template <class Container, class Match, class Traits>
1075 : struct format_functor_container
1076 : {
1077 : format_functor_container(const Container& c) : func(c) {}
1078 :
1079 : template <class OutputIter>
1080 : OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits())
1081 : {
1082 : //typedef typename Match::char_type char_type;
1083 : return BOOST_REGEX_DETAIL_NS::regex_format_imp(i, m, func.begin(), func.end(), f, t);
1084 : }
1085 : private:
1086 : const Container& func;
1087 : format_functor_container(const format_functor_container&);
1088 : format_functor_container& operator=(const format_functor_container&);
1089 : };
1090 :
1091 : template <class Func, class Match, class OutputIterator, class Traits = BOOST_REGEX_DETAIL_NS::trivial_format_traits<typename Match::char_type> >
1092 : struct compute_functor_type
1093 : {
1094 : typedef typename format_traits<Func, Match, OutputIterator>::type tag;
1095 : typedef typename boost::remove_cv< typename boost::remove_pointer<Func>::type>::type maybe_char_type;
1096 :
1097 : typedef typename mpl::if_<
1098 : ::boost::is_same<tag, mpl::int_<0> >, format_functor_c_string<maybe_char_type, Match, Traits>,
1099 : typename mpl::if_<
1100 : ::boost::is_same<tag, mpl::int_<1> >, format_functor_container<Func, Match, Traits>,
1101 : typename mpl::if_<
1102 : ::boost::is_same<tag, mpl::int_<2> >, format_functor1<Func, Match>,
1103 : typename mpl::if_<
1104 : ::boost::is_same<tag, mpl::int_<3> >, format_functor2<Func, Match>,
1105 : format_functor3<Func, Match>
1106 : >::type
1107 : >::type
1108 : >::type
1109 : >::type type;
1110 : };
1111 :
1112 : } // namespace BOOST_REGEX_DETAIL_NS
1113 :
1114 : template <class OutputIterator, class Iterator, class Allocator, class Functor>
1115 : inline OutputIterator regex_format(OutputIterator out,
1116 : const match_results<Iterator, Allocator>& m,
1117 : Functor fmt,
1118 : match_flag_type flags = format_all
1119 : )
1120 : {
1121 : return m.format(out, fmt, flags);
1122 : }
1123 :
1124 : template <class Iterator, class Allocator, class Functor>
1125 : inline std::basic_string<typename match_results<Iterator, Allocator>::char_type> regex_format(const match_results<Iterator, Allocator>& m,
1126 : Functor fmt,
1127 : match_flag_type flags = format_all)
1128 : {
1129 : return m.format(fmt, flags);
1130 : }
1131 :
1132 : #ifdef BOOST_MSVC
1133 : #pragma warning(push)
1134 : #pragma warning(disable: 4103)
1135 : #endif
1136 : #ifdef BOOST_HAS_ABI_HEADERS
1137 : # include BOOST_ABI_SUFFIX
1138 : #endif
1139 : #ifdef BOOST_MSVC
1140 : #pragma warning(pop)
1141 : #endif
1142 :
1143 : } // namespace boost
1144 :
1145 : #endif // BOOST_REGEX_FORMAT_HPP
1146 :
1147 :
1148 :
1149 :
1150 :
1151 :
|