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