blob: 5ec8657dc46b223aa8e49360bbb8784af597249e [file] [log] [blame]
Jeff Thompson86b6d642013-10-17 15:01:56 -07001/*
2 *
3 * Copyright (c) 2004 John Maddock
4 * Copyright 2011 Garmin Ltd. or its subsidiaries
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 cpp_regex_traits.hpp
15 * VERSION see <ndnboost/version.hpp>
16 * DESCRIPTION: Declares regular expression traits class cpp_regex_traits.
17 */
18
19#ifndef NDNBOOST_CPP_REGEX_TRAITS_HPP_INCLUDED
20#define NDNBOOST_CPP_REGEX_TRAITS_HPP_INCLUDED
21
22#include <ndnboost/config.hpp>
23#include <ndnboost/integer.hpp>
24
25#ifndef NDNBOOST_NO_STD_LOCALE
26
27#ifndef NDNBOOST_RE_PAT_EXCEPT_HPP
28#include <ndnboost/regex/pattern_except.hpp>
29#endif
30#ifndef NDNBOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED
31#include <ndnboost/regex/v4/regex_traits_defaults.hpp>
32#endif
33#ifdef NDNBOOST_HAS_THREADS
34#include <ndnboost/regex/pending/static_mutex.hpp>
35#endif
36#ifndef NDNBOOST_REGEX_PRIMARY_TRANSFORM
37#include <ndnboost/regex/v4/primary_transform.hpp>
38#endif
39#ifndef NDNBOOST_REGEX_OBJECT_CACHE_HPP
40#include <ndnboost/regex/pending/object_cache.hpp>
41#endif
42
43#include <istream>
44#include <ios>
45#include <climits>
46
47#ifdef NDNBOOST_MSVC
48#pragma warning(push)
49#pragma warning(disable: 4103)
50#endif
51#ifdef NDNBOOST_HAS_ABI_HEADERS
52# include NDNBOOST_ABI_PREFIX
53#endif
54#ifdef NDNBOOST_MSVC
55#pragma warning(pop)
56#endif
57
58#ifdef NDNBOOST_MSVC
59#pragma warning(push)
60#pragma warning(disable:4786 4251)
61#endif
62
63namespace ndnboost{
64
65//
66// forward declaration is needed by some compilers:
67//
68template <class charT>
69class cpp_regex_traits;
70
71namespace re_detail{
72
73//
74// class parser_buf:
75// acts as a stream buffer which wraps around a pair of pointers:
76//
77template <class charT,
78 class traits = ::std::char_traits<charT> >
79class parser_buf : public ::std::basic_streambuf<charT, traits>
80{
81 typedef ::std::basic_streambuf<charT, traits> base_type;
82 typedef typename base_type::int_type int_type;
83 typedef typename base_type::char_type char_type;
84 typedef typename base_type::pos_type pos_type;
85 typedef ::std::streamsize streamsize;
86 typedef typename base_type::off_type off_type;
87public:
88 parser_buf() : base_type() { setbuf(0, 0); }
89 const charT* getnext() { return this->gptr(); }
90protected:
91 std::basic_streambuf<charT, traits>* setbuf(char_type* s, streamsize n);
92 typename parser_buf<charT, traits>::pos_type seekpos(pos_type sp, ::std::ios_base::openmode which);
93 typename parser_buf<charT, traits>::pos_type seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which);
94private:
95 parser_buf& operator=(const parser_buf&);
96 parser_buf(const parser_buf&);
97};
98
99template<class charT, class traits>
100std::basic_streambuf<charT, traits>*
101parser_buf<charT, traits>::setbuf(char_type* s, streamsize n)
102{
103 this->setg(s, s, s + n);
104 return this;
105}
106
107template<class charT, class traits>
108typename parser_buf<charT, traits>::pos_type
109parser_buf<charT, traits>::seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which)
110{
111 typedef typename ndnboost::int_t<sizeof(way) * CHAR_BIT>::least cast_type;
112
113 if(which & ::std::ios_base::out)
114 return pos_type(off_type(-1));
115 std::ptrdiff_t size = this->egptr() - this->eback();
116 std::ptrdiff_t pos = this->gptr() - this->eback();
117 charT* g = this->eback();
118 switch(static_cast<cast_type>(way))
119 {
120 case ::std::ios_base::beg:
121 if((off < 0) || (off > size))
122 return pos_type(off_type(-1));
123 else
124 this->setg(g, g + off, g + size);
125 break;
126 case ::std::ios_base::end:
127 if((off < 0) || (off > size))
128 return pos_type(off_type(-1));
129 else
130 this->setg(g, g + size - off, g + size);
131 break;
132 case ::std::ios_base::cur:
133 {
134 std::ptrdiff_t newpos = static_cast<std::ptrdiff_t>(pos + off);
135 if((newpos < 0) || (newpos > size))
136 return pos_type(off_type(-1));
137 else
138 this->setg(g, g + newpos, g + size);
139 break;
140 }
141 default: ;
142 }
143#ifdef NDNBOOST_MSVC
144#pragma warning(push)
145#pragma warning(disable:4244)
146#endif
147 return static_cast<pos_type>(this->gptr() - this->eback());
148#ifdef NDNBOOST_MSVC
149#pragma warning(pop)
150#endif
151}
152
153template<class charT, class traits>
154typename parser_buf<charT, traits>::pos_type
155parser_buf<charT, traits>::seekpos(pos_type sp, ::std::ios_base::openmode which)
156{
157 if(which & ::std::ios_base::out)
158 return pos_type(off_type(-1));
159 off_type size = static_cast<off_type>(this->egptr() - this->eback());
160 charT* g = this->eback();
161 if(off_type(sp) <= size)
162 {
163 this->setg(g, g + off_type(sp), g + size);
164 }
165 return pos_type(off_type(-1));
166}
167
168//
169// class cpp_regex_traits_base:
170// acts as a container for locale and the facets we are using.
171//
172template <class charT>
173struct cpp_regex_traits_base
174{
175 cpp_regex_traits_base(const std::locale& l)
176 { imbue(l); }
177 std::locale imbue(const std::locale& l);
178
179 std::locale m_locale;
180 std::ctype<charT> const* m_pctype;
181#ifndef NDNBOOST_NO_STD_MESSAGES
182 std::messages<charT> const* m_pmessages;
183#endif
184 std::collate<charT> const* m_pcollate;
185
186 bool operator<(const cpp_regex_traits_base& b)const
187 {
188 if(m_pctype == b.m_pctype)
189 {
190#ifndef NDNBOOST_NO_STD_MESSAGES
191 if(m_pmessages == b.m_pmessages)
192 {
193 return m_pcollate < b.m_pcollate;
194 }
195 return m_pmessages < b.m_pmessages;
196#else
197 return m_pcollate < b.m_pcollate;
198#endif
199 }
200 return m_pctype < b.m_pctype;
201 }
202 bool operator==(const cpp_regex_traits_base& b)const
203 {
204 return (m_pctype == b.m_pctype)
205#ifndef NDNBOOST_NO_STD_MESSAGES
206 && (m_pmessages == b.m_pmessages)
207#endif
208 && (m_pcollate == b.m_pcollate);
209 }
210};
211
212template <class charT>
213std::locale cpp_regex_traits_base<charT>::imbue(const std::locale& l)
214{
215 std::locale result(m_locale);
216 m_locale = l;
217 m_pctype = &NDNBOOST_USE_FACET(std::ctype<charT>, l);
218#ifndef NDNBOOST_NO_STD_MESSAGES
219 m_pmessages = NDNBOOST_HAS_FACET(std::messages<charT>, l) ? &NDNBOOST_USE_FACET(std::messages<charT>, l) : 0;
220#endif
221 m_pcollate = &NDNBOOST_USE_FACET(std::collate<charT>, l);
222 return result;
223}
224
225//
226// class cpp_regex_traits_char_layer:
227// implements methods that require specialisation for narrow characters:
228//
229template <class charT>
230class cpp_regex_traits_char_layer : public cpp_regex_traits_base<charT>
231{
232 typedef std::basic_string<charT> string_type;
233 typedef std::map<charT, regex_constants::syntax_type> map_type;
234 typedef typename map_type::const_iterator map_iterator_type;
235public:
236 cpp_regex_traits_char_layer(const std::locale& l)
237 : cpp_regex_traits_base<charT>(l)
238 {
239 init();
240 }
241 cpp_regex_traits_char_layer(const cpp_regex_traits_base<charT>& b)
242 : cpp_regex_traits_base<charT>(b)
243 {
244 init();
245 }
246 void init();
247
248 regex_constants::syntax_type syntax_type(charT c)const
249 {
250 map_iterator_type i = m_char_map.find(c);
251 return ((i == m_char_map.end()) ? 0 : i->second);
252 }
253 regex_constants::escape_syntax_type escape_syntax_type(charT c) const
254 {
255 map_iterator_type i = m_char_map.find(c);
256 if(i == m_char_map.end())
257 {
258 if(this->m_pctype->is(std::ctype_base::lower, c)) return regex_constants::escape_type_class;
259 if(this->m_pctype->is(std::ctype_base::upper, c)) return regex_constants::escape_type_not_class;
260 return 0;
261 }
262 return i->second;
263 }
264
265private:
266 string_type get_default_message(regex_constants::syntax_type);
267 // TODO: use a hash table when available!
268 map_type m_char_map;
269};
270
271template <class charT>
272void cpp_regex_traits_char_layer<charT>::init()
273{
274 // we need to start by initialising our syntax map so we know which
275 // character is used for which purpose:
276#ifndef NDNBOOST_NO_STD_MESSAGES
277#ifndef __IBMCPP__
278 typename std::messages<charT>::catalog cat = static_cast<std::messages<char>::catalog>(-1);
279#else
280 typename std::messages<charT>::catalog cat = reinterpret_cast<std::messages<char>::catalog>(-1);
281#endif
282 std::string cat_name(cpp_regex_traits<charT>::get_catalog_name());
283 if(cat_name.size() && (this->m_pmessages != 0))
284 {
285 cat = this->m_pmessages->open(
286 cat_name,
287 this->m_locale);
288 if((int)cat < 0)
289 {
290 std::string m("Unable to open message catalog: ");
291 std::runtime_error err(m + cat_name);
292 ndnboost::re_detail::raise_runtime_error(err);
293 }
294 }
295 //
296 // if we have a valid catalog then load our messages:
297 //
298 if((int)cat >= 0)
299 {
300#ifndef NDNBOOST_NO_EXCEPTIONS
301 try{
302#endif
303 for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
304 {
305 string_type mss = this->m_pmessages->get(cat, 0, i, get_default_message(i));
306 for(typename string_type::size_type j = 0; j < mss.size(); ++j)
307 {
308 m_char_map[mss[j]] = i;
309 }
310 }
311 this->m_pmessages->close(cat);
312#ifndef NDNBOOST_NO_EXCEPTIONS
313 }
314 catch(...)
315 {
316 if(this->m_pmessages)
317 this->m_pmessages->close(cat);
318 throw;
319 }
320#endif
321 }
322 else
323 {
324#endif
325 for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
326 {
327 const char* ptr = get_default_syntax(i);
328 while(ptr && *ptr)
329 {
330 m_char_map[this->m_pctype->widen(*ptr)] = i;
331 ++ptr;
332 }
333 }
334#ifndef NDNBOOST_NO_STD_MESSAGES
335 }
336#endif
337}
338
339template <class charT>
340typename cpp_regex_traits_char_layer<charT>::string_type
341 cpp_regex_traits_char_layer<charT>::get_default_message(regex_constants::syntax_type i)
342{
343 const char* ptr = get_default_syntax(i);
344 string_type result;
345 while(ptr && *ptr)
346 {
347 result.append(1, this->m_pctype->widen(*ptr));
348 ++ptr;
349 }
350 return result;
351}
352
353//
354// specialised version for narrow characters:
355//
356template <>
357class NDNBOOST_REGEX_DECL cpp_regex_traits_char_layer<char> : public cpp_regex_traits_base<char>
358{
359 typedef std::string string_type;
360public:
361 cpp_regex_traits_char_layer(const std::locale& l)
362 : cpp_regex_traits_base<char>(l)
363 {
364 init();
365 }
366 cpp_regex_traits_char_layer(const cpp_regex_traits_base<char>& l)
367 : cpp_regex_traits_base<char>(l)
368 {
369 init();
370 }
371
372 regex_constants::syntax_type syntax_type(char c)const
373 {
374 return m_char_map[static_cast<unsigned char>(c)];
375 }
376 regex_constants::escape_syntax_type escape_syntax_type(char c) const
377 {
378 return m_char_map[static_cast<unsigned char>(c)];
379 }
380
381private:
382 regex_constants::syntax_type m_char_map[1u << CHAR_BIT];
383 void init();
384};
385
386#ifdef NDNBOOST_REGEX_BUGGY_CTYPE_FACET
387enum
388{
389 char_class_space=1<<0,
390 char_class_print=1<<1,
391 char_class_cntrl=1<<2,
392 char_class_upper=1<<3,
393 char_class_lower=1<<4,
394 char_class_alpha=1<<5,
395 char_class_digit=1<<6,
396 char_class_punct=1<<7,
397 char_class_xdigit=1<<8,
398 char_class_alnum=char_class_alpha|char_class_digit,
399 char_class_graph=char_class_alnum|char_class_punct,
400 char_class_blank=1<<9,
401 char_class_word=1<<10,
402 char_class_unicode=1<<11,
403 char_class_horizontal_space=1<<12,
404 char_class_vertical_space=1<<13
405};
406
407#endif
408
409//
410// class cpp_regex_traits_implementation:
411// provides pimpl implementation for cpp_regex_traits.
412//
413template <class charT>
414class cpp_regex_traits_implementation : public cpp_regex_traits_char_layer<charT>
415{
416public:
417 typedef typename cpp_regex_traits<charT>::char_class_type char_class_type;
418 typedef typename std::ctype<charT>::mask native_mask_type;
419#ifndef NDNBOOST_REGEX_BUGGY_CTYPE_FACET
420 NDNBOOST_STATIC_CONSTANT(char_class_type, mask_blank = 1u << 24);
421 NDNBOOST_STATIC_CONSTANT(char_class_type, mask_word = 1u << 25);
422 NDNBOOST_STATIC_CONSTANT(char_class_type, mask_unicode = 1u << 26);
423 NDNBOOST_STATIC_CONSTANT(char_class_type, mask_horizontal = 1u << 27);
424 NDNBOOST_STATIC_CONSTANT(char_class_type, mask_vertical = 1u << 28);
425#endif
426
427 typedef std::basic_string<charT> string_type;
428 typedef charT char_type;
429 //cpp_regex_traits_implementation();
430 cpp_regex_traits_implementation(const std::locale& l)
431 : cpp_regex_traits_char_layer<charT>(l)
432 {
433 init();
434 }
435 cpp_regex_traits_implementation(const cpp_regex_traits_base<charT>& l)
436 : cpp_regex_traits_char_layer<charT>(l)
437 {
438 init();
439 }
440 std::string error_string(regex_constants::error_type n) const
441 {
442 if(!m_error_strings.empty())
443 {
444 std::map<int, std::string>::const_iterator p = m_error_strings.find(n);
445 return (p == m_error_strings.end()) ? std::string(get_default_error_string(n)) : p->second;
446 }
447 return get_default_error_string(n);
448 }
449 char_class_type lookup_classname(const charT* p1, const charT* p2) const
450 {
451 char_class_type result = lookup_classname_imp(p1, p2);
452 if(result == 0)
453 {
454 string_type temp(p1, p2);
455 this->m_pctype->tolower(&*temp.begin(), &*temp.begin() + temp.size());
456 result = lookup_classname_imp(&*temp.begin(), &*temp.begin() + temp.size());
457 }
458 return result;
459 }
460 string_type lookup_collatename(const charT* p1, const charT* p2) const;
461 string_type transform_primary(const charT* p1, const charT* p2) const;
462 string_type transform(const charT* p1, const charT* p2) const;
463private:
464 std::map<int, std::string> m_error_strings; // error messages indexed by numberic ID
465 std::map<string_type, char_class_type> m_custom_class_names; // character class names
466 std::map<string_type, string_type> m_custom_collate_names; // collating element names
467 unsigned m_collate_type; // the form of the collation string
468 charT m_collate_delim; // the collation group delimiter
469 //
470 // helpers:
471 //
472 char_class_type lookup_classname_imp(const charT* p1, const charT* p2) const;
473 void init();
474#ifdef NDNBOOST_REGEX_BUGGY_CTYPE_FACET
475public:
476 bool isctype(charT c, char_class_type m)const;
477#endif
478};
479
480#ifndef NDNBOOST_REGEX_BUGGY_CTYPE_FACET
481#if !defined(NDNBOOST_NO_INCLASS_MEMBER_INITIALIZATION)
482
483template <class charT>
484typename cpp_regex_traits_implementation<charT>::char_class_type const cpp_regex_traits_implementation<charT>::mask_blank;
485template <class charT>
486typename cpp_regex_traits_implementation<charT>::char_class_type const cpp_regex_traits_implementation<charT>::mask_word;
487template <class charT>
488typename cpp_regex_traits_implementation<charT>::char_class_type const cpp_regex_traits_implementation<charT>::mask_unicode;
489template <class charT>
490typename cpp_regex_traits_implementation<charT>::char_class_type const cpp_regex_traits_implementation<charT>::mask_vertical;
491template <class charT>
492typename cpp_regex_traits_implementation<charT>::char_class_type const cpp_regex_traits_implementation<charT>::mask_horizontal;
493
494#endif
495#endif
496
497template <class charT>
498typename cpp_regex_traits_implementation<charT>::string_type
499 cpp_regex_traits_implementation<charT>::transform_primary(const charT* p1, const charT* p2) const
500{
501 //
502 // PRECONDITIONS:
503 //
504 // A bug in gcc 3.2 (and maybe other versions as well) treats
505 // p1 as a null terminated string, for efficiency reasons
506 // we work around this elsewhere, but just assert here that
507 // we adhere to gcc's (buggy) preconditions...
508 //
509 NDNBOOST_ASSERT(*p2 == 0);
510
511 string_type result;
512 //
513 // swallowing all exceptions here is a bad idea
514 // however at least one std lib will always throw
515 // std::bad_alloc for certain arguments...
516 //
517#ifndef NDNBOOST_NO_EXCEPTIONS
518 try{
519#endif
520 //
521 // What we do here depends upon the format of the sort key returned by
522 // sort key returned by this->transform:
523 //
524 switch(m_collate_type)
525 {
526 case sort_C:
527 case sort_unknown:
528 // the best we can do is translate to lower case, then get a regular sort key:
529 {
530 result.assign(p1, p2);
531 this->m_pctype->tolower(&*result.begin(), &*result.begin() + result.size());
532 result = this->m_pcollate->transform(&*result.begin(), &*result.begin() + result.size());
533 break;
534 }
535 case sort_fixed:
536 {
537 // get a regular sort key, and then truncate it:
538 result.assign(this->m_pcollate->transform(p1, p2));
539 result.erase(this->m_collate_delim);
540 break;
541 }
542 case sort_delim:
543 // get a regular sort key, and then truncate everything after the delim:
544 result.assign(this->m_pcollate->transform(p1, p2));
545 std::size_t i;
546 for(i = 0; i < result.size(); ++i)
547 {
548 if(result[i] == m_collate_delim)
549 break;
550 }
551 result.erase(i);
552 break;
553 }
554#ifndef NDNBOOST_NO_EXCEPTIONS
555 }catch(...){}
556#endif
557 while(result.size() && (charT(0) == *result.rbegin()))
558 result.erase(result.size() - 1);
559 if(result.empty())
560 {
561 // character is ignorable at the primary level:
562 result = string_type(1, charT(0));
563 }
564 return result;
565}
566
567template <class charT>
568typename cpp_regex_traits_implementation<charT>::string_type
569 cpp_regex_traits_implementation<charT>::transform(const charT* p1, const charT* p2) const
570{
571 //
572 // PRECONDITIONS:
573 //
574 // A bug in gcc 3.2 (and maybe other versions as well) treats
575 // p1 as a null terminated string, for efficiency reasons
576 // we work around this elsewhere, but just assert here that
577 // we adhere to gcc's (buggy) preconditions...
578 //
579 NDNBOOST_ASSERT(*p2 == 0);
580 //
581 // swallowing all exceptions here is a bad idea
582 // however at least one std lib will always throw
583 // std::bad_alloc for certain arguments...
584 //
585 string_type result;
586#ifndef NDNBOOST_NO_EXCEPTIONS
587 try{
588#endif
589 result = this->m_pcollate->transform(p1, p2);
590 //
591 // Borland's STLPort version returns a NULL-terminated
592 // string that has garbage at the end - each call to
593 // std::collate<wchar_t>::transform returns a different string!
594 // So as a workaround, we'll truncate the string at the first NULL
595 // which _seems_ to work....
596#if NDNBOOST_WORKAROUND(__BORLANDC__, < 0x580)
597 result.erase(result.find(charT(0)));
598#else
599 //
600 // some implementations (Dinkumware) append unnecessary trailing \0's:
601 while(result.size() && (charT(0) == *result.rbegin()))
602 result.erase(result.size() - 1);
603#endif
604 NDNBOOST_ASSERT(std::find(result.begin(), result.end(), charT(0)) == result.end());
605#ifndef NDNBOOST_NO_EXCEPTIONS
606 }
607 catch(...)
608 {
609 }
610#endif
611 return result;
612}
613
614
615template <class charT>
616typename cpp_regex_traits_implementation<charT>::string_type
617 cpp_regex_traits_implementation<charT>::lookup_collatename(const charT* p1, const charT* p2) const
618{
619 typedef typename std::map<string_type, string_type>::const_iterator iter_type;
620 if(m_custom_collate_names.size())
621 {
622 iter_type pos = m_custom_collate_names.find(string_type(p1, p2));
623 if(pos != m_custom_collate_names.end())
624 return pos->second;
625 }
626#if !defined(NDNBOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\
627 && !NDNBOOST_WORKAROUND(NDNBOOST_MSVC, < 1300)\
628 && !NDNBOOST_WORKAROUND(__BORLANDC__, <= 0x0551)
629 std::string name(p1, p2);
630#else
631 std::string name;
632 const charT* p0 = p1;
633 while(p0 != p2)
634 name.append(1, char(*p0++));
635#endif
636 name = lookup_default_collate_name(name);
637#if !defined(NDNBOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\
638 && !NDNBOOST_WORKAROUND(NDNBOOST_MSVC, < 1300)\
639 && !NDNBOOST_WORKAROUND(__BORLANDC__, <= 0x0551)
640 if(name.size())
641 return string_type(name.begin(), name.end());
642#else
643 if(name.size())
644 {
645 string_type result;
646 typedef std::string::const_iterator iter;
647 iter b = name.begin();
648 iter e = name.end();
649 while(b != e)
650 result.append(1, charT(*b++));
651 return result;
652 }
653#endif
654 if(p2 - p1 == 1)
655 return string_type(1, *p1);
656 return string_type();
657}
658
659template <class charT>
660void cpp_regex_traits_implementation<charT>::init()
661{
662#ifndef NDNBOOST_NO_STD_MESSAGES
663#ifndef __IBMCPP__
664 typename std::messages<charT>::catalog cat = static_cast<std::messages<char>::catalog>(-1);
665#else
666 typename std::messages<charT>::catalog cat = reinterpret_cast<std::messages<char>::catalog>(-1);
667#endif
668 std::string cat_name(cpp_regex_traits<charT>::get_catalog_name());
669 if(cat_name.size() && (this->m_pmessages != 0))
670 {
671 cat = this->m_pmessages->open(
672 cat_name,
673 this->m_locale);
674 if((int)cat < 0)
675 {
676 std::string m("Unable to open message catalog: ");
677 std::runtime_error err(m + cat_name);
678 ndnboost::re_detail::raise_runtime_error(err);
679 }
680 }
681 //
682 // if we have a valid catalog then load our messages:
683 //
684 if((int)cat >= 0)
685 {
686 //
687 // Error messages:
688 //
689 for(ndnboost::regex_constants::error_type i = static_cast<ndnboost::regex_constants::error_type>(0);
690 i <= ndnboost::regex_constants::error_unknown;
691 i = static_cast<ndnboost::regex_constants::error_type>(i + 1))
692 {
693 const char* p = get_default_error_string(i);
694 string_type default_message;
695 while(*p)
696 {
697 default_message.append(1, this->m_pctype->widen(*p));
698 ++p;
699 }
700 string_type s = this->m_pmessages->get(cat, 0, i+200, default_message);
701 std::string result;
702 for(std::string::size_type j = 0; j < s.size(); ++j)
703 {
704 result.append(1, this->m_pctype->narrow(s[j], 0));
705 }
706 m_error_strings[i] = result;
707 }
708 //
709 // Custom class names:
710 //
711#ifndef NDNBOOST_REGEX_BUGGY_CTYPE_FACET
712 static const char_class_type masks[16] =
713 {
714 std::ctype<charT>::alnum,
715 std::ctype<charT>::alpha,
716 std::ctype<charT>::cntrl,
717 std::ctype<charT>::digit,
718 std::ctype<charT>::graph,
719 cpp_regex_traits_implementation<charT>::mask_horizontal,
720 std::ctype<charT>::lower,
721 std::ctype<charT>::print,
722 std::ctype<charT>::punct,
723 std::ctype<charT>::space,
724 std::ctype<charT>::upper,
725 cpp_regex_traits_implementation<charT>::mask_vertical,
726 std::ctype<charT>::xdigit,
727 cpp_regex_traits_implementation<charT>::mask_blank,
728 cpp_regex_traits_implementation<charT>::mask_word,
729 cpp_regex_traits_implementation<charT>::mask_unicode,
730 };
731#else
732 static const char_class_type masks[16] =
733 {
734 ::ndnboost::re_detail::char_class_alnum,
735 ::ndnboost::re_detail::char_class_alpha,
736 ::ndnboost::re_detail::char_class_cntrl,
737 ::ndnboost::re_detail::char_class_digit,
738 ::ndnboost::re_detail::char_class_graph,
739 ::ndnboost::re_detail::char_class_horizontal_space,
740 ::ndnboost::re_detail::char_class_lower,
741 ::ndnboost::re_detail::char_class_print,
742 ::ndnboost::re_detail::char_class_punct,
743 ::ndnboost::re_detail::char_class_space,
744 ::ndnboost::re_detail::char_class_upper,
745 ::ndnboost::re_detail::char_class_vertical_space,
746 ::ndnboost::re_detail::char_class_xdigit,
747 ::ndnboost::re_detail::char_class_blank,
748 ::ndnboost::re_detail::char_class_word,
749 ::ndnboost::re_detail::char_class_unicode,
750 };
751#endif
752 static const string_type null_string;
753 for(unsigned int j = 0; j <= 13; ++j)
754 {
755 string_type s(this->m_pmessages->get(cat, 0, j+300, null_string));
756 if(s.size())
757 this->m_custom_class_names[s] = masks[j];
758 }
759 }
760#endif
761 //
762 // get the collation format used by m_pcollate:
763 //
764 m_collate_type = re_detail::find_sort_syntax(this, &m_collate_delim);
765}
766
767template <class charT>
768typename cpp_regex_traits_implementation<charT>::char_class_type
769 cpp_regex_traits_implementation<charT>::lookup_classname_imp(const charT* p1, const charT* p2) const
770{
771#ifndef NDNBOOST_REGEX_BUGGY_CTYPE_FACET
772 static const char_class_type masks[22] =
773 {
774 0,
775 std::ctype<char>::alnum,
776 std::ctype<char>::alpha,
777 cpp_regex_traits_implementation<charT>::mask_blank,
778 std::ctype<char>::cntrl,
779 std::ctype<char>::digit,
780 std::ctype<char>::digit,
781 std::ctype<char>::graph,
782 cpp_regex_traits_implementation<charT>::mask_horizontal,
783 std::ctype<char>::lower,
784 std::ctype<char>::lower,
785 std::ctype<char>::print,
786 std::ctype<char>::punct,
787 std::ctype<char>::space,
788 std::ctype<char>::space,
789 std::ctype<char>::upper,
790 cpp_regex_traits_implementation<charT>::mask_unicode,
791 std::ctype<char>::upper,
792 cpp_regex_traits_implementation<charT>::mask_vertical,
793 std::ctype<char>::alnum | cpp_regex_traits_implementation<charT>::mask_word,
794 std::ctype<char>::alnum | cpp_regex_traits_implementation<charT>::mask_word,
795 std::ctype<char>::xdigit,
796 };
797#else
798 static const char_class_type masks[22] =
799 {
800 0,
801 ::ndnboost::re_detail::char_class_alnum,
802 ::ndnboost::re_detail::char_class_alpha,
803 ::ndnboost::re_detail::char_class_blank,
804 ::ndnboost::re_detail::char_class_cntrl,
805 ::ndnboost::re_detail::char_class_digit,
806 ::ndnboost::re_detail::char_class_digit,
807 ::ndnboost::re_detail::char_class_graph,
808 ::ndnboost::re_detail::char_class_horizontal_space,
809 ::ndnboost::re_detail::char_class_lower,
810 ::ndnboost::re_detail::char_class_lower,
811 ::ndnboost::re_detail::char_class_print,
812 ::ndnboost::re_detail::char_class_punct,
813 ::ndnboost::re_detail::char_class_space,
814 ::ndnboost::re_detail::char_class_space,
815 ::ndnboost::re_detail::char_class_upper,
816 ::ndnboost::re_detail::char_class_unicode,
817 ::ndnboost::re_detail::char_class_upper,
818 ::ndnboost::re_detail::char_class_vertical_space,
819 ::ndnboost::re_detail::char_class_alnum | ::ndnboost::re_detail::char_class_word,
820 ::ndnboost::re_detail::char_class_alnum | ::ndnboost::re_detail::char_class_word,
821 ::ndnboost::re_detail::char_class_xdigit,
822 };
823#endif
824 if(m_custom_class_names.size())
825 {
826 typedef typename std::map<std::basic_string<charT>, char_class_type>::const_iterator map_iter;
827 map_iter pos = m_custom_class_names.find(string_type(p1, p2));
828 if(pos != m_custom_class_names.end())
829 return pos->second;
830 }
831 std::size_t state_id = 1 + re_detail::get_default_class_id(p1, p2);
832 NDNBOOST_ASSERT(state_id < sizeof(masks) / sizeof(masks[0]));
833 return masks[state_id];
834}
835
836#ifdef NDNBOOST_REGEX_BUGGY_CTYPE_FACET
837template <class charT>
838bool cpp_regex_traits_implementation<charT>::isctype(const charT c, char_class_type mask) const
839{
840 return
841 ((mask & ::ndnboost::re_detail::char_class_space) && (this->m_pctype->is(std::ctype<charT>::space, c)))
842 || ((mask & ::ndnboost::re_detail::char_class_print) && (this->m_pctype->is(std::ctype<charT>::print, c)))
843 || ((mask & ::ndnboost::re_detail::char_class_cntrl) && (this->m_pctype->is(std::ctype<charT>::cntrl, c)))
844 || ((mask & ::ndnboost::re_detail::char_class_upper) && (this->m_pctype->is(std::ctype<charT>::upper, c)))
845 || ((mask & ::ndnboost::re_detail::char_class_lower) && (this->m_pctype->is(std::ctype<charT>::lower, c)))
846 || ((mask & ::ndnboost::re_detail::char_class_alpha) && (this->m_pctype->is(std::ctype<charT>::alpha, c)))
847 || ((mask & ::ndnboost::re_detail::char_class_digit) && (this->m_pctype->is(std::ctype<charT>::digit, c)))
848 || ((mask & ::ndnboost::re_detail::char_class_punct) && (this->m_pctype->is(std::ctype<charT>::punct, c)))
849 || ((mask & ::ndnboost::re_detail::char_class_xdigit) && (this->m_pctype->is(std::ctype<charT>::xdigit, c)))
850 || ((mask & ::ndnboost::re_detail::char_class_blank) && (this->m_pctype->is(std::ctype<charT>::space, c)) && !::ndnboost::re_detail::is_separator(c))
851 || ((mask & ::ndnboost::re_detail::char_class_word) && (c == '_'))
852 || ((mask & ::ndnboost::re_detail::char_class_unicode) && ::ndnboost::re_detail::is_extended(c))
853 || ((mask & ::ndnboost::re_detail::char_class_vertical_space) && (is_separator(c) || (c == '\v')))
854 || ((mask & ::ndnboost::re_detail::char_class_horizontal_space) && this->m_pctype->is(std::ctype<charT>::space, c) && !(is_separator(c) || (c == '\v')));
855}
856#endif
857
858
859template <class charT>
860inline ndnboost::shared_ptr<const cpp_regex_traits_implementation<charT> > create_cpp_regex_traits(const std::locale& l NDNBOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(charT))
861{
862 cpp_regex_traits_base<charT> key(l);
863 return ::ndnboost::object_cache<cpp_regex_traits_base<charT>, cpp_regex_traits_implementation<charT> >::get(key, 5);
864}
865
866} // re_detail
867
868template <class charT>
869class cpp_regex_traits
870{
871private:
872 typedef std::ctype<charT> ctype_type;
873public:
874 typedef charT char_type;
875 typedef std::size_t size_type;
876 typedef std::basic_string<char_type> string_type;
877 typedef std::locale locale_type;
878 typedef ndnboost::uint_least32_t char_class_type;
879
880 struct boost_extensions_tag{};
881
882 cpp_regex_traits()
883 : m_pimpl(re_detail::create_cpp_regex_traits<charT>(std::locale()))
884 { }
885 static size_type length(const char_type* p)
886 {
887 return std::char_traits<charT>::length(p);
888 }
889 regex_constants::syntax_type syntax_type(charT c)const
890 {
891 return m_pimpl->syntax_type(c);
892 }
893 regex_constants::escape_syntax_type escape_syntax_type(charT c) const
894 {
895 return m_pimpl->escape_syntax_type(c);
896 }
897 charT translate(charT c) const
898 {
899 return c;
900 }
901 charT translate_nocase(charT c) const
902 {
903 return m_pimpl->m_pctype->tolower(c);
904 }
905 charT translate(charT c, bool icase) const
906 {
907 return icase ? m_pimpl->m_pctype->tolower(c) : c;
908 }
909 charT tolower(charT c) const
910 {
911 return m_pimpl->m_pctype->tolower(c);
912 }
913 charT toupper(charT c) const
914 {
915 return m_pimpl->m_pctype->toupper(c);
916 }
917 string_type transform(const charT* p1, const charT* p2) const
918 {
919 return m_pimpl->transform(p1, p2);
920 }
921 string_type transform_primary(const charT* p1, const charT* p2) const
922 {
923 return m_pimpl->transform_primary(p1, p2);
924 }
925 char_class_type lookup_classname(const charT* p1, const charT* p2) const
926 {
927 return m_pimpl->lookup_classname(p1, p2);
928 }
929 string_type lookup_collatename(const charT* p1, const charT* p2) const
930 {
931 return m_pimpl->lookup_collatename(p1, p2);
932 }
933 bool isctype(charT c, char_class_type f) const
934 {
935#ifndef NDNBOOST_REGEX_BUGGY_CTYPE_FACET
936 typedef typename std::ctype<charT>::mask ctype_mask;
937
938 static const ctype_mask mask_base =
939 static_cast<ctype_mask>(
940 std::ctype<charT>::alnum
941 | std::ctype<charT>::alpha
942 | std::ctype<charT>::cntrl
943 | std::ctype<charT>::digit
944 | std::ctype<charT>::graph
945 | std::ctype<charT>::lower
946 | std::ctype<charT>::print
947 | std::ctype<charT>::punct
948 | std::ctype<charT>::space
949 | std::ctype<charT>::upper
950 | std::ctype<charT>::xdigit);
951
952 if((f & mask_base)
953 && (m_pimpl->m_pctype->is(
954 static_cast<ctype_mask>(f & mask_base), c)))
955 return true;
956 else if((f & re_detail::cpp_regex_traits_implementation<charT>::mask_unicode) && re_detail::is_extended(c))
957 return true;
958 else if((f & re_detail::cpp_regex_traits_implementation<charT>::mask_word) && (c == '_'))
959 return true;
960 else if((f & re_detail::cpp_regex_traits_implementation<charT>::mask_blank)
961 && m_pimpl->m_pctype->is(std::ctype<charT>::space, c)
962 && !re_detail::is_separator(c))
963 return true;
964 else if((f & re_detail::cpp_regex_traits_implementation<charT>::mask_vertical)
965 && (::ndnboost::re_detail::is_separator(c) || (c == '\v')))
966 return true;
967 else if((f & re_detail::cpp_regex_traits_implementation<charT>::mask_horizontal)
968 && this->isctype(c, std::ctype<charT>::space) && !this->isctype(c, re_detail::cpp_regex_traits_implementation<charT>::mask_vertical))
969 return true;
970 return false;
971#else
972 return m_pimpl->isctype(c, f);
973#endif
974 }
975 int toi(const charT*& p1, const charT* p2, int radix)const;
976 int value(charT c, int radix)const
977 {
978 const charT* pc = &c;
979 return toi(pc, pc + 1, radix);
980 }
981 locale_type imbue(locale_type l)
982 {
983 std::locale result(getloc());
984 m_pimpl = re_detail::create_cpp_regex_traits<charT>(l);
985 return result;
986 }
987 locale_type getloc()const
988 {
989 return m_pimpl->m_locale;
990 }
991 std::string error_string(regex_constants::error_type n) const
992 {
993 return m_pimpl->error_string(n);
994 }
995
996 //
997 // extension:
998 // set the name of the message catalog in use (defaults to "boost_regex").
999 //
1000 static std::string catalog_name(const std::string& name);
1001 static std::string get_catalog_name();
1002
1003private:
1004 ndnboost::shared_ptr<const re_detail::cpp_regex_traits_implementation<charT> > m_pimpl;
1005 //
1006 // catalog name handler:
1007 //
1008 static std::string& get_catalog_name_inst();
1009
1010#ifdef NDNBOOST_HAS_THREADS
1011 static static_mutex& get_mutex_inst();
1012#endif
1013};
1014
1015
1016template <class charT>
1017int cpp_regex_traits<charT>::toi(const charT*& first, const charT* last, int radix)const
1018{
1019 re_detail::parser_buf<charT> sbuf; // buffer for parsing numbers.
1020 std::basic_istream<charT> is(&sbuf); // stream for parsing numbers.
1021
1022 // we do NOT want to parse any thousands separators inside the stream:
1023 last = std::find(first, last, NDNBOOST_USE_FACET(std::numpunct<charT>, is.getloc()).thousands_sep());
1024
1025 sbuf.pubsetbuf(const_cast<charT*>(static_cast<const charT*>(first)), static_cast<std::streamsize>(last-first));
1026 is.clear();
1027 if(std::abs(radix) == 16) is >> std::hex;
1028 else if(std::abs(radix) == 8) is >> std::oct;
1029 else is >> std::dec;
1030 int val;
1031 if(is >> val)
1032 {
1033 first = first + ((last - first) - sbuf.in_avail());
1034 return val;
1035 }
1036 else
1037 return -1;
1038}
1039
1040template <class charT>
1041std::string cpp_regex_traits<charT>::catalog_name(const std::string& name)
1042{
1043#ifdef NDNBOOST_HAS_THREADS
1044 static_mutex::scoped_lock lk(get_mutex_inst());
1045#endif
1046 std::string result(get_catalog_name_inst());
1047 get_catalog_name_inst() = name;
1048 return result;
1049}
1050
1051template <class charT>
1052std::string& cpp_regex_traits<charT>::get_catalog_name_inst()
1053{
1054 static std::string s_name;
1055 return s_name;
1056}
1057
1058template <class charT>
1059std::string cpp_regex_traits<charT>::get_catalog_name()
1060{
1061#ifdef NDNBOOST_HAS_THREADS
1062 static_mutex::scoped_lock lk(get_mutex_inst());
1063#endif
1064 std::string result(get_catalog_name_inst());
1065 return result;
1066}
1067
1068#ifdef NDNBOOST_HAS_THREADS
1069template <class charT>
1070static_mutex& cpp_regex_traits<charT>::get_mutex_inst()
1071{
1072 static static_mutex s_mutex = NDNBOOST_STATIC_MUTEX_INIT;
1073 return s_mutex;
1074}
1075#endif
1076
1077
1078} // boost
1079
1080#ifdef NDNBOOST_MSVC
1081#pragma warning(pop)
1082#endif
1083
1084#ifdef NDNBOOST_MSVC
1085#pragma warning(push)
1086#pragma warning(disable: 4103)
1087#endif
1088#ifdef NDNBOOST_HAS_ABI_HEADERS
1089# include NDNBOOST_ABI_SUFFIX
1090#endif
1091#ifdef NDNBOOST_MSVC
1092#pragma warning(pop)
1093#endif
1094
1095#endif
1096
1097#endif
1098
1099