Chris@16: /* Chris@16: * Chris@16: * Copyright (c) 2004 John Maddock Chris@16: * Copyright 2011 Garmin Ltd. or its subsidiaries Chris@16: * Chris@16: * Use, modification and distribution are subject to the Chris@16: * Boost Software License, Version 1.0. (See accompanying file Chris@16: * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: * Chris@16: */ Chris@16: Chris@16: /* Chris@16: * LOCATION: see http://www.boost.org for most recent version. Chris@16: * FILE cpp_regex_traits.hpp Chris@16: * VERSION see Chris@16: * DESCRIPTION: Declares regular expression traits class cpp_regex_traits. Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_CPP_REGEX_TRAITS_HPP_INCLUDED Chris@16: #define BOOST_CPP_REGEX_TRAITS_HPP_INCLUDED Chris@16: Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: Chris@16: #ifndef BOOST_NO_STD_LOCALE Chris@16: Chris@16: #ifndef BOOST_RE_PAT_EXCEPT_HPP Chris@16: #include Chris@16: #endif Chris@16: #ifndef BOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED Chris@16: #include Chris@16: #endif Chris@16: #ifdef BOOST_HAS_THREADS Chris@16: #include Chris@16: #endif Chris@16: #ifndef BOOST_REGEX_PRIMARY_TRANSFORM Chris@16: #include Chris@16: #endif Chris@16: #ifndef BOOST_REGEX_OBJECT_CACHE_HPP Chris@16: #include Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable: 4103) Chris@16: #endif Chris@16: #ifdef BOOST_HAS_ABI_HEADERS Chris@16: # include BOOST_ABI_PREFIX Chris@16: #endif Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable:4786 4251) Chris@16: #endif Chris@16: Chris@16: namespace boost{ Chris@16: Chris@16: // Chris@16: // forward declaration is needed by some compilers: Chris@16: // Chris@16: template Chris@16: class cpp_regex_traits; Chris@16: Chris@16: namespace re_detail{ Chris@16: Chris@16: // Chris@16: // class parser_buf: Chris@16: // acts as a stream buffer which wraps around a pair of pointers: Chris@16: // Chris@16: template > Chris@16: class parser_buf : public ::std::basic_streambuf Chris@16: { Chris@16: typedef ::std::basic_streambuf base_type; Chris@16: typedef typename base_type::int_type int_type; Chris@16: typedef typename base_type::char_type char_type; Chris@16: typedef typename base_type::pos_type pos_type; Chris@16: typedef ::std::streamsize streamsize; Chris@16: typedef typename base_type::off_type off_type; Chris@16: public: Chris@16: parser_buf() : base_type() { setbuf(0, 0); } Chris@16: const charT* getnext() { return this->gptr(); } Chris@16: protected: Chris@16: std::basic_streambuf* setbuf(char_type* s, streamsize n); Chris@16: typename parser_buf::pos_type seekpos(pos_type sp, ::std::ios_base::openmode which); Chris@16: typename parser_buf::pos_type seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which); Chris@16: private: Chris@16: parser_buf& operator=(const parser_buf&); Chris@16: parser_buf(const parser_buf&); Chris@16: }; Chris@16: Chris@16: template Chris@16: std::basic_streambuf* Chris@16: parser_buf::setbuf(char_type* s, streamsize n) Chris@16: { Chris@16: this->setg(s, s, s + n); Chris@16: return this; Chris@16: } Chris@16: Chris@16: template Chris@16: typename parser_buf::pos_type Chris@16: parser_buf::seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) Chris@16: { Chris@16: typedef typename boost::int_t::least cast_type; Chris@16: Chris@16: if(which & ::std::ios_base::out) Chris@16: return pos_type(off_type(-1)); Chris@16: std::ptrdiff_t size = this->egptr() - this->eback(); Chris@16: std::ptrdiff_t pos = this->gptr() - this->eback(); Chris@16: charT* g = this->eback(); Chris@16: switch(static_cast(way)) Chris@16: { Chris@16: case ::std::ios_base::beg: Chris@16: if((off < 0) || (off > size)) Chris@16: return pos_type(off_type(-1)); Chris@16: else Chris@16: this->setg(g, g + off, g + size); Chris@16: break; Chris@16: case ::std::ios_base::end: Chris@16: if((off < 0) || (off > size)) Chris@16: return pos_type(off_type(-1)); Chris@16: else Chris@16: this->setg(g, g + size - off, g + size); Chris@16: break; Chris@16: case ::std::ios_base::cur: Chris@16: { Chris@16: std::ptrdiff_t newpos = static_cast(pos + off); Chris@16: if((newpos < 0) || (newpos > size)) Chris@16: return pos_type(off_type(-1)); Chris@16: else Chris@16: this->setg(g, g + newpos, g + size); Chris@16: break; Chris@16: } Chris@16: default: ; Chris@16: } Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable:4244) Chris@16: #endif Chris@16: return static_cast(this->gptr() - this->eback()); Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: } Chris@16: Chris@16: template Chris@16: typename parser_buf::pos_type Chris@16: parser_buf::seekpos(pos_type sp, ::std::ios_base::openmode which) Chris@16: { Chris@16: if(which & ::std::ios_base::out) Chris@16: return pos_type(off_type(-1)); Chris@16: off_type size = static_cast(this->egptr() - this->eback()); Chris@16: charT* g = this->eback(); Chris@16: if(off_type(sp) <= size) Chris@16: { Chris@16: this->setg(g, g + off_type(sp), g + size); Chris@16: } Chris@16: return pos_type(off_type(-1)); Chris@16: } Chris@16: Chris@16: // Chris@16: // class cpp_regex_traits_base: Chris@16: // acts as a container for locale and the facets we are using. Chris@16: // Chris@16: template Chris@16: struct cpp_regex_traits_base Chris@16: { Chris@16: cpp_regex_traits_base(const std::locale& l) Chris@16: { imbue(l); } Chris@16: std::locale imbue(const std::locale& l); Chris@16: Chris@16: std::locale m_locale; Chris@16: std::ctype const* m_pctype; Chris@16: #ifndef BOOST_NO_STD_MESSAGES Chris@16: std::messages const* m_pmessages; Chris@16: #endif Chris@16: std::collate const* m_pcollate; Chris@16: Chris@16: bool operator<(const cpp_regex_traits_base& b)const Chris@16: { Chris@16: if(m_pctype == b.m_pctype) Chris@16: { Chris@16: #ifndef BOOST_NO_STD_MESSAGES Chris@16: if(m_pmessages == b.m_pmessages) Chris@16: { Chris@16: return m_pcollate < b.m_pcollate; Chris@16: } Chris@16: return m_pmessages < b.m_pmessages; Chris@16: #else Chris@16: return m_pcollate < b.m_pcollate; Chris@16: #endif Chris@16: } Chris@16: return m_pctype < b.m_pctype; Chris@16: } Chris@16: bool operator==(const cpp_regex_traits_base& b)const Chris@16: { Chris@16: return (m_pctype == b.m_pctype) Chris@16: #ifndef BOOST_NO_STD_MESSAGES Chris@16: && (m_pmessages == b.m_pmessages) Chris@16: #endif Chris@16: && (m_pcollate == b.m_pcollate); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: std::locale cpp_regex_traits_base::imbue(const std::locale& l) Chris@16: { Chris@16: std::locale result(m_locale); Chris@16: m_locale = l; Chris@16: m_pctype = &BOOST_USE_FACET(std::ctype, l); Chris@16: #ifndef BOOST_NO_STD_MESSAGES Chris@16: m_pmessages = BOOST_HAS_FACET(std::messages, l) ? &BOOST_USE_FACET(std::messages, l) : 0; Chris@16: #endif Chris@16: m_pcollate = &BOOST_USE_FACET(std::collate, l); Chris@16: return result; Chris@16: } Chris@16: Chris@16: // Chris@16: // class cpp_regex_traits_char_layer: Chris@16: // implements methods that require specialisation for narrow characters: Chris@16: // Chris@16: template Chris@16: class cpp_regex_traits_char_layer : public cpp_regex_traits_base Chris@16: { Chris@16: typedef std::basic_string string_type; Chris@16: typedef std::map map_type; Chris@16: typedef typename map_type::const_iterator map_iterator_type; Chris@16: public: Chris@16: cpp_regex_traits_char_layer(const std::locale& l) Chris@16: : cpp_regex_traits_base(l) Chris@16: { Chris@16: init(); Chris@16: } Chris@16: cpp_regex_traits_char_layer(const cpp_regex_traits_base& b) Chris@16: : cpp_regex_traits_base(b) Chris@16: { Chris@16: init(); Chris@16: } Chris@16: void init(); Chris@16: Chris@16: regex_constants::syntax_type syntax_type(charT c)const Chris@16: { Chris@16: map_iterator_type i = m_char_map.find(c); Chris@16: return ((i == m_char_map.end()) ? 0 : i->second); Chris@16: } Chris@16: regex_constants::escape_syntax_type escape_syntax_type(charT c) const Chris@16: { Chris@16: map_iterator_type i = m_char_map.find(c); Chris@16: if(i == m_char_map.end()) Chris@16: { Chris@16: if(this->m_pctype->is(std::ctype_base::lower, c)) return regex_constants::escape_type_class; Chris@16: if(this->m_pctype->is(std::ctype_base::upper, c)) return regex_constants::escape_type_not_class; Chris@16: return 0; Chris@16: } Chris@16: return i->second; Chris@16: } Chris@16: Chris@16: private: Chris@16: string_type get_default_message(regex_constants::syntax_type); Chris@16: // TODO: use a hash table when available! Chris@16: map_type m_char_map; Chris@16: }; Chris@16: Chris@16: template Chris@16: void cpp_regex_traits_char_layer::init() Chris@16: { Chris@16: // we need to start by initialising our syntax map so we know which Chris@16: // character is used for which purpose: Chris@16: #ifndef BOOST_NO_STD_MESSAGES Chris@16: #ifndef __IBMCPP__ Chris@16: typename std::messages::catalog cat = static_cast::catalog>(-1); Chris@16: #else Chris@16: typename std::messages::catalog cat = reinterpret_cast::catalog>(-1); Chris@16: #endif Chris@16: std::string cat_name(cpp_regex_traits::get_catalog_name()); Chris@16: if(cat_name.size() && (this->m_pmessages != 0)) Chris@16: { Chris@16: cat = this->m_pmessages->open( Chris@16: cat_name, Chris@16: this->m_locale); Chris@16: if((int)cat < 0) Chris@16: { Chris@16: std::string m("Unable to open message catalog: "); Chris@16: std::runtime_error err(m + cat_name); Chris@16: boost::re_detail::raise_runtime_error(err); Chris@16: } Chris@16: } Chris@16: // Chris@16: // if we have a valid catalog then load our messages: Chris@16: // Chris@16: if((int)cat >= 0) Chris@16: { Chris@16: #ifndef BOOST_NO_EXCEPTIONS Chris@16: try{ Chris@16: #endif Chris@16: for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) Chris@16: { Chris@16: string_type mss = this->m_pmessages->get(cat, 0, i, get_default_message(i)); Chris@16: for(typename string_type::size_type j = 0; j < mss.size(); ++j) Chris@16: { Chris@16: m_char_map[mss[j]] = i; Chris@16: } Chris@16: } Chris@16: this->m_pmessages->close(cat); Chris@16: #ifndef BOOST_NO_EXCEPTIONS Chris@16: } Chris@16: catch(...) Chris@16: { Chris@16: if(this->m_pmessages) Chris@16: this->m_pmessages->close(cat); Chris@16: throw; Chris@16: } Chris@16: #endif Chris@16: } Chris@16: else Chris@16: { Chris@16: #endif Chris@16: for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) Chris@16: { Chris@16: const char* ptr = get_default_syntax(i); Chris@16: while(ptr && *ptr) Chris@16: { Chris@16: m_char_map[this->m_pctype->widen(*ptr)] = i; Chris@16: ++ptr; Chris@16: } Chris@16: } Chris@16: #ifndef BOOST_NO_STD_MESSAGES Chris@16: } Chris@16: #endif Chris@16: } Chris@16: Chris@16: template Chris@16: typename cpp_regex_traits_char_layer::string_type Chris@16: cpp_regex_traits_char_layer::get_default_message(regex_constants::syntax_type i) Chris@16: { Chris@16: const char* ptr = get_default_syntax(i); Chris@16: string_type result; Chris@16: while(ptr && *ptr) Chris@16: { Chris@16: result.append(1, this->m_pctype->widen(*ptr)); Chris@16: ++ptr; Chris@16: } Chris@16: return result; Chris@16: } Chris@16: Chris@16: // Chris@16: // specialised version for narrow characters: Chris@16: // Chris@16: template <> Chris@16: class BOOST_REGEX_DECL cpp_regex_traits_char_layer : public cpp_regex_traits_base Chris@16: { Chris@16: typedef std::string string_type; Chris@16: public: Chris@16: cpp_regex_traits_char_layer(const std::locale& l) Chris@16: : cpp_regex_traits_base(l) Chris@16: { Chris@16: init(); Chris@16: } Chris@16: cpp_regex_traits_char_layer(const cpp_regex_traits_base& l) Chris@16: : cpp_regex_traits_base(l) Chris@16: { Chris@16: init(); Chris@16: } Chris@16: Chris@16: regex_constants::syntax_type syntax_type(char c)const Chris@16: { Chris@16: return m_char_map[static_cast(c)]; Chris@16: } Chris@16: regex_constants::escape_syntax_type escape_syntax_type(char c) const Chris@16: { Chris@16: return m_char_map[static_cast(c)]; Chris@16: } Chris@16: Chris@16: private: Chris@16: regex_constants::syntax_type m_char_map[1u << CHAR_BIT]; Chris@16: void init(); Chris@16: }; Chris@16: Chris@16: #ifdef BOOST_REGEX_BUGGY_CTYPE_FACET Chris@16: enum Chris@16: { Chris@16: char_class_space=1<<0, Chris@16: char_class_print=1<<1, Chris@16: char_class_cntrl=1<<2, Chris@16: char_class_upper=1<<3, Chris@16: char_class_lower=1<<4, Chris@16: char_class_alpha=1<<5, Chris@16: char_class_digit=1<<6, Chris@16: char_class_punct=1<<7, Chris@16: char_class_xdigit=1<<8, Chris@16: char_class_alnum=char_class_alpha|char_class_digit, Chris@16: char_class_graph=char_class_alnum|char_class_punct, Chris@16: char_class_blank=1<<9, Chris@16: char_class_word=1<<10, Chris@16: char_class_unicode=1<<11, Chris@16: char_class_horizontal_space=1<<12, Chris@16: char_class_vertical_space=1<<13 Chris@16: }; Chris@16: Chris@16: #endif Chris@16: Chris@16: // Chris@16: // class cpp_regex_traits_implementation: Chris@16: // provides pimpl implementation for cpp_regex_traits. Chris@16: // Chris@16: template Chris@16: class cpp_regex_traits_implementation : public cpp_regex_traits_char_layer Chris@16: { Chris@16: public: Chris@16: typedef typename cpp_regex_traits::char_class_type char_class_type; Chris@16: typedef typename std::ctype::mask native_mask_type; Chris@16: #ifndef BOOST_REGEX_BUGGY_CTYPE_FACET Chris@16: BOOST_STATIC_CONSTANT(char_class_type, mask_blank = 1u << 24); Chris@16: BOOST_STATIC_CONSTANT(char_class_type, mask_word = 1u << 25); Chris@16: BOOST_STATIC_CONSTANT(char_class_type, mask_unicode = 1u << 26); Chris@16: BOOST_STATIC_CONSTANT(char_class_type, mask_horizontal = 1u << 27); Chris@16: BOOST_STATIC_CONSTANT(char_class_type, mask_vertical = 1u << 28); Chris@16: #endif Chris@16: Chris@16: typedef std::basic_string string_type; Chris@16: typedef charT char_type; Chris@16: //cpp_regex_traits_implementation(); Chris@16: cpp_regex_traits_implementation(const std::locale& l) Chris@16: : cpp_regex_traits_char_layer(l) Chris@16: { Chris@16: init(); Chris@16: } Chris@16: cpp_regex_traits_implementation(const cpp_regex_traits_base& l) Chris@16: : cpp_regex_traits_char_layer(l) Chris@16: { Chris@16: init(); Chris@16: } Chris@16: std::string error_string(regex_constants::error_type n) const Chris@16: { Chris@16: if(!m_error_strings.empty()) Chris@16: { Chris@16: std::map::const_iterator p = m_error_strings.find(n); Chris@16: return (p == m_error_strings.end()) ? std::string(get_default_error_string(n)) : p->second; Chris@16: } Chris@16: return get_default_error_string(n); Chris@16: } Chris@16: char_class_type lookup_classname(const charT* p1, const charT* p2) const Chris@16: { Chris@16: char_class_type result = lookup_classname_imp(p1, p2); Chris@16: if(result == 0) Chris@16: { Chris@16: string_type temp(p1, p2); Chris@16: this->m_pctype->tolower(&*temp.begin(), &*temp.begin() + temp.size()); Chris@16: result = lookup_classname_imp(&*temp.begin(), &*temp.begin() + temp.size()); Chris@16: } Chris@16: return result; Chris@16: } Chris@16: string_type lookup_collatename(const charT* p1, const charT* p2) const; Chris@16: string_type transform_primary(const charT* p1, const charT* p2) const; Chris@16: string_type transform(const charT* p1, const charT* p2) const; Chris@16: private: Chris@16: std::map m_error_strings; // error messages indexed by numberic ID Chris@16: std::map m_custom_class_names; // character class names Chris@16: std::map m_custom_collate_names; // collating element names Chris@16: unsigned m_collate_type; // the form of the collation string Chris@16: charT m_collate_delim; // the collation group delimiter Chris@16: // Chris@16: // helpers: Chris@16: // Chris@16: char_class_type lookup_classname_imp(const charT* p1, const charT* p2) const; Chris@16: void init(); Chris@16: #ifdef BOOST_REGEX_BUGGY_CTYPE_FACET Chris@16: public: Chris@16: bool isctype(charT c, char_class_type m)const; Chris@16: #endif Chris@16: }; Chris@16: Chris@16: #ifndef BOOST_REGEX_BUGGY_CTYPE_FACET Chris@16: #if !defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) Chris@16: Chris@16: template Chris@16: typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_blank; Chris@16: template Chris@16: typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_word; Chris@16: template Chris@16: typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_unicode; Chris@16: template Chris@16: typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_vertical; Chris@16: template Chris@16: typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_horizontal; Chris@16: Chris@16: #endif Chris@16: #endif Chris@16: Chris@16: template Chris@16: typename cpp_regex_traits_implementation::string_type Chris@16: cpp_regex_traits_implementation::transform_primary(const charT* p1, const charT* p2) const Chris@16: { Chris@16: // Chris@16: // PRECONDITIONS: Chris@16: // Chris@16: // A bug in gcc 3.2 (and maybe other versions as well) treats Chris@16: // p1 as a null terminated string, for efficiency reasons Chris@16: // we work around this elsewhere, but just assert here that Chris@16: // we adhere to gcc's (buggy) preconditions... Chris@16: // Chris@16: BOOST_ASSERT(*p2 == 0); Chris@16: string_type result; Chris@101: #if defined(_CPPLIB_VER) Chris@101: // Chris@101: // A bug in VC11 and 12 causes the program to hang if we pass a null-string Chris@101: // to std::collate::transform, but only for certain locales :-( Chris@101: // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). Chris@101: // Chris@101: if(*p1 == 0) Chris@101: { Chris@101: return string_type(1, charT(0)); Chris@101: } Chris@101: #endif Chris@16: // Chris@16: // swallowing all exceptions here is a bad idea Chris@16: // however at least one std lib will always throw Chris@16: // std::bad_alloc for certain arguments... Chris@16: // Chris@16: #ifndef BOOST_NO_EXCEPTIONS Chris@16: try{ Chris@16: #endif Chris@16: // Chris@16: // What we do here depends upon the format of the sort key returned by Chris@16: // sort key returned by this->transform: Chris@16: // Chris@16: switch(m_collate_type) Chris@16: { Chris@16: case sort_C: Chris@16: case sort_unknown: Chris@16: // the best we can do is translate to lower case, then get a regular sort key: Chris@16: { Chris@16: result.assign(p1, p2); Chris@16: this->m_pctype->tolower(&*result.begin(), &*result.begin() + result.size()); Chris@16: result = this->m_pcollate->transform(&*result.begin(), &*result.begin() + result.size()); Chris@16: break; Chris@16: } Chris@16: case sort_fixed: Chris@16: { Chris@16: // get a regular sort key, and then truncate it: Chris@16: result.assign(this->m_pcollate->transform(p1, p2)); Chris@16: result.erase(this->m_collate_delim); Chris@16: break; Chris@16: } Chris@16: case sort_delim: Chris@16: // get a regular sort key, and then truncate everything after the delim: Chris@16: result.assign(this->m_pcollate->transform(p1, p2)); Chris@16: std::size_t i; Chris@16: for(i = 0; i < result.size(); ++i) Chris@16: { Chris@16: if(result[i] == m_collate_delim) Chris@16: break; Chris@16: } Chris@16: result.erase(i); Chris@16: break; Chris@16: } Chris@16: #ifndef BOOST_NO_EXCEPTIONS Chris@16: }catch(...){} Chris@16: #endif Chris@16: while(result.size() && (charT(0) == *result.rbegin())) Chris@16: result.erase(result.size() - 1); Chris@16: if(result.empty()) Chris@16: { Chris@16: // character is ignorable at the primary level: Chris@16: result = string_type(1, charT(0)); Chris@16: } Chris@16: return result; Chris@16: } Chris@16: Chris@16: template Chris@16: typename cpp_regex_traits_implementation::string_type Chris@16: cpp_regex_traits_implementation::transform(const charT* p1, const charT* p2) const Chris@16: { Chris@16: // Chris@16: // PRECONDITIONS: Chris@16: // Chris@16: // A bug in gcc 3.2 (and maybe other versions as well) treats Chris@16: // p1 as a null terminated string, for efficiency reasons Chris@16: // we work around this elsewhere, but just assert here that Chris@16: // we adhere to gcc's (buggy) preconditions... Chris@16: // Chris@16: BOOST_ASSERT(*p2 == 0); Chris@16: // Chris@16: // swallowing all exceptions here is a bad idea Chris@16: // however at least one std lib will always throw Chris@16: // std::bad_alloc for certain arguments... Chris@16: // Chris@101: string_type result, result2; Chris@101: #if defined(_CPPLIB_VER) Chris@101: // Chris@101: // A bug in VC11 and 12 causes the program to hang if we pass a null-string Chris@101: // to std::collate::transform, but only for certain locales :-( Chris@101: // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). Chris@101: // Chris@101: if(*p1 == 0) Chris@101: { Chris@101: return result; Chris@101: } Chris@101: #endif Chris@16: #ifndef BOOST_NO_EXCEPTIONS Chris@16: try{ Chris@16: #endif Chris@16: result = this->m_pcollate->transform(p1, p2); Chris@16: // Chris@16: // Borland's STLPort version returns a NULL-terminated Chris@16: // string that has garbage at the end - each call to Chris@16: // std::collate::transform returns a different string! Chris@16: // So as a workaround, we'll truncate the string at the first NULL Chris@16: // which _seems_ to work.... Chris@16: #if BOOST_WORKAROUND(__BORLANDC__, < 0x580) Chris@16: result.erase(result.find(charT(0))); Chris@16: #else Chris@16: // Chris@16: // some implementations (Dinkumware) append unnecessary trailing \0's: Chris@16: while(result.size() && (charT(0) == *result.rbegin())) Chris@16: result.erase(result.size() - 1); Chris@16: #endif Chris@101: // Chris@101: // We may have NULL's used as separators between sections of the collate string, Chris@101: // an example would be Boost.Locale. We have no way to detect this case via Chris@101: // #defines since this can be used with any compiler/platform combination. Chris@101: // Unfortunately our state machine (which was devised when all implementations Chris@101: // used underlying C language API's) can't cope with that case. One workaround Chris@101: // is to replace each character with 2, fortunately this code isn't used that Chris@101: // much as this is now slower than before :-( Chris@101: // Chris@101: typedef typename make_unsigned::type uchar_type; Chris@101: result2.reserve(result.size() * 2 + 2); Chris@101: for(unsigned i = 0; i < result.size(); ++i) Chris@101: { Chris@101: if(static_cast(result[i]) == (std::numeric_limits::max)()) Chris@101: { Chris@101: result2.append(1, charT((std::numeric_limits::max)())).append(1, charT('b')); Chris@101: } Chris@101: else Chris@101: { Chris@101: result2.append(1, static_cast(1 + static_cast(result[i]))).append(1, charT('b') - 1); Chris@101: } Chris@101: } Chris@101: BOOST_ASSERT(std::find(result2.begin(), result2.end(), charT(0)) == result2.end()); Chris@16: #ifndef BOOST_NO_EXCEPTIONS Chris@16: } Chris@16: catch(...) Chris@16: { Chris@16: } Chris@16: #endif Chris@101: return result2; Chris@16: } Chris@16: Chris@16: Chris@16: template Chris@16: typename cpp_regex_traits_implementation::string_type Chris@16: cpp_regex_traits_implementation::lookup_collatename(const charT* p1, const charT* p2) const Chris@16: { Chris@16: typedef typename std::map::const_iterator iter_type; Chris@16: if(m_custom_collate_names.size()) Chris@16: { Chris@16: iter_type pos = m_custom_collate_names.find(string_type(p1, p2)); Chris@16: if(pos != m_custom_collate_names.end()) Chris@16: return pos->second; Chris@16: } Chris@16: #if !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\ Chris@16: && !BOOST_WORKAROUND(__BORLANDC__, <= 0x0551) Chris@16: std::string name(p1, p2); Chris@16: #else Chris@16: std::string name; Chris@16: const charT* p0 = p1; Chris@16: while(p0 != p2) Chris@16: name.append(1, char(*p0++)); Chris@16: #endif Chris@16: name = lookup_default_collate_name(name); Chris@16: #if !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\ Chris@16: && !BOOST_WORKAROUND(__BORLANDC__, <= 0x0551) Chris@16: if(name.size()) Chris@16: return string_type(name.begin(), name.end()); Chris@16: #else Chris@16: if(name.size()) Chris@16: { Chris@16: string_type result; Chris@16: typedef std::string::const_iterator iter; Chris@16: iter b = name.begin(); Chris@16: iter e = name.end(); Chris@16: while(b != e) Chris@16: result.append(1, charT(*b++)); Chris@16: return result; Chris@16: } Chris@16: #endif Chris@16: if(p2 - p1 == 1) Chris@16: return string_type(1, *p1); Chris@16: return string_type(); Chris@16: } Chris@16: Chris@16: template Chris@16: void cpp_regex_traits_implementation::init() Chris@16: { Chris@16: #ifndef BOOST_NO_STD_MESSAGES Chris@16: #ifndef __IBMCPP__ Chris@16: typename std::messages::catalog cat = static_cast::catalog>(-1); Chris@16: #else Chris@16: typename std::messages::catalog cat = reinterpret_cast::catalog>(-1); Chris@16: #endif Chris@16: std::string cat_name(cpp_regex_traits::get_catalog_name()); Chris@16: if(cat_name.size() && (this->m_pmessages != 0)) Chris@16: { Chris@16: cat = this->m_pmessages->open( Chris@16: cat_name, Chris@16: this->m_locale); Chris@16: if((int)cat < 0) Chris@16: { Chris@16: std::string m("Unable to open message catalog: "); Chris@16: std::runtime_error err(m + cat_name); Chris@16: boost::re_detail::raise_runtime_error(err); Chris@16: } Chris@16: } Chris@16: // Chris@16: // if we have a valid catalog then load our messages: Chris@16: // Chris@16: if((int)cat >= 0) Chris@16: { Chris@16: // Chris@16: // Error messages: Chris@16: // Chris@16: for(boost::regex_constants::error_type i = static_cast(0); Chris@16: i <= boost::regex_constants::error_unknown; Chris@16: i = static_cast(i + 1)) Chris@16: { Chris@16: const char* p = get_default_error_string(i); Chris@16: string_type default_message; Chris@16: while(*p) Chris@16: { Chris@16: default_message.append(1, this->m_pctype->widen(*p)); Chris@16: ++p; Chris@16: } Chris@16: string_type s = this->m_pmessages->get(cat, 0, i+200, default_message); Chris@16: std::string result; Chris@16: for(std::string::size_type j = 0; j < s.size(); ++j) Chris@16: { Chris@16: result.append(1, this->m_pctype->narrow(s[j], 0)); Chris@16: } Chris@16: m_error_strings[i] = result; Chris@16: } Chris@16: // Chris@16: // Custom class names: Chris@16: // Chris@16: #ifndef BOOST_REGEX_BUGGY_CTYPE_FACET Chris@16: static const char_class_type masks[16] = Chris@16: { Chris@16: std::ctype::alnum, Chris@16: std::ctype::alpha, Chris@16: std::ctype::cntrl, Chris@16: std::ctype::digit, Chris@16: std::ctype::graph, Chris@16: cpp_regex_traits_implementation::mask_horizontal, Chris@16: std::ctype::lower, Chris@16: std::ctype::print, Chris@16: std::ctype::punct, Chris@16: std::ctype::space, Chris@16: std::ctype::upper, Chris@16: cpp_regex_traits_implementation::mask_vertical, Chris@16: std::ctype::xdigit, Chris@16: cpp_regex_traits_implementation::mask_blank, Chris@16: cpp_regex_traits_implementation::mask_word, Chris@16: cpp_regex_traits_implementation::mask_unicode, Chris@16: }; Chris@16: #else Chris@16: static const char_class_type masks[16] = Chris@16: { Chris@16: ::boost::re_detail::char_class_alnum, Chris@16: ::boost::re_detail::char_class_alpha, Chris@16: ::boost::re_detail::char_class_cntrl, Chris@16: ::boost::re_detail::char_class_digit, Chris@16: ::boost::re_detail::char_class_graph, Chris@16: ::boost::re_detail::char_class_horizontal_space, Chris@16: ::boost::re_detail::char_class_lower, Chris@16: ::boost::re_detail::char_class_print, Chris@16: ::boost::re_detail::char_class_punct, Chris@16: ::boost::re_detail::char_class_space, Chris@16: ::boost::re_detail::char_class_upper, Chris@16: ::boost::re_detail::char_class_vertical_space, Chris@16: ::boost::re_detail::char_class_xdigit, Chris@16: ::boost::re_detail::char_class_blank, Chris@16: ::boost::re_detail::char_class_word, Chris@16: ::boost::re_detail::char_class_unicode, Chris@16: }; Chris@16: #endif Chris@16: static const string_type null_string; Chris@16: for(unsigned int j = 0; j <= 13; ++j) Chris@16: { Chris@16: string_type s(this->m_pmessages->get(cat, 0, j+300, null_string)); Chris@16: if(s.size()) Chris@16: this->m_custom_class_names[s] = masks[j]; Chris@16: } Chris@16: } Chris@16: #endif Chris@16: // Chris@16: // get the collation format used by m_pcollate: Chris@16: // Chris@16: m_collate_type = re_detail::find_sort_syntax(this, &m_collate_delim); Chris@16: } Chris@16: Chris@16: template Chris@16: typename cpp_regex_traits_implementation::char_class_type Chris@16: cpp_regex_traits_implementation::lookup_classname_imp(const charT* p1, const charT* p2) const Chris@16: { Chris@16: #ifndef BOOST_REGEX_BUGGY_CTYPE_FACET Chris@16: static const char_class_type masks[22] = Chris@16: { Chris@16: 0, Chris@16: std::ctype::alnum, Chris@16: std::ctype::alpha, Chris@16: cpp_regex_traits_implementation::mask_blank, Chris@16: std::ctype::cntrl, Chris@16: std::ctype::digit, Chris@16: std::ctype::digit, Chris@16: std::ctype::graph, Chris@16: cpp_regex_traits_implementation::mask_horizontal, Chris@16: std::ctype::lower, Chris@16: std::ctype::lower, Chris@16: std::ctype::print, Chris@16: std::ctype::punct, Chris@16: std::ctype::space, Chris@16: std::ctype::space, Chris@16: std::ctype::upper, Chris@16: cpp_regex_traits_implementation::mask_unicode, Chris@16: std::ctype::upper, Chris@16: cpp_regex_traits_implementation::mask_vertical, Chris@16: std::ctype::alnum | cpp_regex_traits_implementation::mask_word, Chris@16: std::ctype::alnum | cpp_regex_traits_implementation::mask_word, Chris@16: std::ctype::xdigit, Chris@16: }; Chris@16: #else Chris@16: static const char_class_type masks[22] = Chris@16: { Chris@16: 0, Chris@16: ::boost::re_detail::char_class_alnum, Chris@16: ::boost::re_detail::char_class_alpha, Chris@16: ::boost::re_detail::char_class_blank, Chris@16: ::boost::re_detail::char_class_cntrl, Chris@16: ::boost::re_detail::char_class_digit, Chris@16: ::boost::re_detail::char_class_digit, Chris@16: ::boost::re_detail::char_class_graph, Chris@16: ::boost::re_detail::char_class_horizontal_space, Chris@16: ::boost::re_detail::char_class_lower, Chris@16: ::boost::re_detail::char_class_lower, Chris@16: ::boost::re_detail::char_class_print, Chris@16: ::boost::re_detail::char_class_punct, Chris@16: ::boost::re_detail::char_class_space, Chris@16: ::boost::re_detail::char_class_space, Chris@16: ::boost::re_detail::char_class_upper, Chris@16: ::boost::re_detail::char_class_unicode, Chris@16: ::boost::re_detail::char_class_upper, Chris@16: ::boost::re_detail::char_class_vertical_space, Chris@16: ::boost::re_detail::char_class_alnum | ::boost::re_detail::char_class_word, Chris@16: ::boost::re_detail::char_class_alnum | ::boost::re_detail::char_class_word, Chris@16: ::boost::re_detail::char_class_xdigit, Chris@16: }; Chris@16: #endif Chris@16: if(m_custom_class_names.size()) Chris@16: { Chris@16: typedef typename std::map, char_class_type>::const_iterator map_iter; Chris@16: map_iter pos = m_custom_class_names.find(string_type(p1, p2)); Chris@16: if(pos != m_custom_class_names.end()) Chris@16: return pos->second; Chris@16: } Chris@16: std::size_t state_id = 1 + re_detail::get_default_class_id(p1, p2); Chris@16: BOOST_ASSERT(state_id < sizeof(masks) / sizeof(masks[0])); Chris@16: return masks[state_id]; Chris@16: } Chris@16: Chris@16: #ifdef BOOST_REGEX_BUGGY_CTYPE_FACET Chris@16: template Chris@16: bool cpp_regex_traits_implementation::isctype(const charT c, char_class_type mask) const Chris@16: { Chris@16: return Chris@16: ((mask & ::boost::re_detail::char_class_space) && (this->m_pctype->is(std::ctype::space, c))) Chris@16: || ((mask & ::boost::re_detail::char_class_print) && (this->m_pctype->is(std::ctype::print, c))) Chris@16: || ((mask & ::boost::re_detail::char_class_cntrl) && (this->m_pctype->is(std::ctype::cntrl, c))) Chris@16: || ((mask & ::boost::re_detail::char_class_upper) && (this->m_pctype->is(std::ctype::upper, c))) Chris@16: || ((mask & ::boost::re_detail::char_class_lower) && (this->m_pctype->is(std::ctype::lower, c))) Chris@16: || ((mask & ::boost::re_detail::char_class_alpha) && (this->m_pctype->is(std::ctype::alpha, c))) Chris@16: || ((mask & ::boost::re_detail::char_class_digit) && (this->m_pctype->is(std::ctype::digit, c))) Chris@16: || ((mask & ::boost::re_detail::char_class_punct) && (this->m_pctype->is(std::ctype::punct, c))) Chris@16: || ((mask & ::boost::re_detail::char_class_xdigit) && (this->m_pctype->is(std::ctype::xdigit, c))) Chris@16: || ((mask & ::boost::re_detail::char_class_blank) && (this->m_pctype->is(std::ctype::space, c)) && !::boost::re_detail::is_separator(c)) Chris@16: || ((mask & ::boost::re_detail::char_class_word) && (c == '_')) Chris@16: || ((mask & ::boost::re_detail::char_class_unicode) && ::boost::re_detail::is_extended(c)) Chris@16: || ((mask & ::boost::re_detail::char_class_vertical_space) && (is_separator(c) || (c == '\v'))) Chris@16: || ((mask & ::boost::re_detail::char_class_horizontal_space) && this->m_pctype->is(std::ctype::space, c) && !(is_separator(c) || (c == '\v'))); Chris@16: } Chris@16: #endif Chris@16: Chris@16: Chris@16: template Chris@101: inline boost::shared_ptr > create_cpp_regex_traits(const std::locale& l) Chris@16: { Chris@16: cpp_regex_traits_base key(l); Chris@16: return ::boost::object_cache, cpp_regex_traits_implementation >::get(key, 5); Chris@16: } Chris@16: Chris@16: } // re_detail Chris@16: Chris@16: template Chris@16: class cpp_regex_traits Chris@16: { Chris@16: private: Chris@16: typedef std::ctype ctype_type; Chris@16: public: Chris@16: typedef charT char_type; Chris@16: typedef std::size_t size_type; Chris@16: typedef std::basic_string string_type; Chris@16: typedef std::locale locale_type; Chris@16: typedef boost::uint_least32_t char_class_type; Chris@16: Chris@16: struct boost_extensions_tag{}; Chris@16: Chris@16: cpp_regex_traits() Chris@16: : m_pimpl(re_detail::create_cpp_regex_traits(std::locale())) Chris@16: { } Chris@16: static size_type length(const char_type* p) Chris@16: { Chris@16: return std::char_traits::length(p); Chris@16: } Chris@16: regex_constants::syntax_type syntax_type(charT c)const Chris@16: { Chris@16: return m_pimpl->syntax_type(c); Chris@16: } Chris@16: regex_constants::escape_syntax_type escape_syntax_type(charT c) const Chris@16: { Chris@16: return m_pimpl->escape_syntax_type(c); Chris@16: } Chris@16: charT translate(charT c) const Chris@16: { Chris@16: return c; Chris@16: } Chris@16: charT translate_nocase(charT c) const Chris@16: { Chris@16: return m_pimpl->m_pctype->tolower(c); Chris@16: } Chris@16: charT translate(charT c, bool icase) const Chris@16: { Chris@16: return icase ? m_pimpl->m_pctype->tolower(c) : c; Chris@16: } Chris@16: charT tolower(charT c) const Chris@16: { Chris@16: return m_pimpl->m_pctype->tolower(c); Chris@16: } Chris@16: charT toupper(charT c) const Chris@16: { Chris@16: return m_pimpl->m_pctype->toupper(c); Chris@16: } Chris@16: string_type transform(const charT* p1, const charT* p2) const Chris@16: { Chris@16: return m_pimpl->transform(p1, p2); Chris@16: } Chris@16: string_type transform_primary(const charT* p1, const charT* p2) const Chris@16: { Chris@16: return m_pimpl->transform_primary(p1, p2); Chris@16: } Chris@16: char_class_type lookup_classname(const charT* p1, const charT* p2) const Chris@16: { Chris@16: return m_pimpl->lookup_classname(p1, p2); Chris@16: } Chris@16: string_type lookup_collatename(const charT* p1, const charT* p2) const Chris@16: { Chris@16: return m_pimpl->lookup_collatename(p1, p2); Chris@16: } Chris@16: bool isctype(charT c, char_class_type f) const Chris@16: { Chris@16: #ifndef BOOST_REGEX_BUGGY_CTYPE_FACET Chris@16: typedef typename std::ctype::mask ctype_mask; Chris@16: Chris@16: static const ctype_mask mask_base = Chris@16: static_cast( Chris@16: std::ctype::alnum Chris@16: | std::ctype::alpha Chris@16: | std::ctype::cntrl Chris@16: | std::ctype::digit Chris@16: | std::ctype::graph Chris@16: | std::ctype::lower Chris@16: | std::ctype::print Chris@16: | std::ctype::punct Chris@16: | std::ctype::space Chris@16: | std::ctype::upper Chris@16: | std::ctype::xdigit); Chris@16: Chris@16: if((f & mask_base) Chris@16: && (m_pimpl->m_pctype->is( Chris@16: static_cast(f & mask_base), c))) Chris@16: return true; Chris@16: else if((f & re_detail::cpp_regex_traits_implementation::mask_unicode) && re_detail::is_extended(c)) Chris@16: return true; Chris@16: else if((f & re_detail::cpp_regex_traits_implementation::mask_word) && (c == '_')) Chris@16: return true; Chris@16: else if((f & re_detail::cpp_regex_traits_implementation::mask_blank) Chris@16: && m_pimpl->m_pctype->is(std::ctype::space, c) Chris@16: && !re_detail::is_separator(c)) Chris@16: return true; Chris@16: else if((f & re_detail::cpp_regex_traits_implementation::mask_vertical) Chris@16: && (::boost::re_detail::is_separator(c) || (c == '\v'))) Chris@16: return true; Chris@16: else if((f & re_detail::cpp_regex_traits_implementation::mask_horizontal) Chris@16: && this->isctype(c, std::ctype::space) && !this->isctype(c, re_detail::cpp_regex_traits_implementation::mask_vertical)) Chris@16: return true; Chris@16: return false; Chris@16: #else Chris@16: return m_pimpl->isctype(c, f); Chris@16: #endif Chris@16: } Chris@16: int toi(const charT*& p1, const charT* p2, int radix)const; Chris@16: int value(charT c, int radix)const Chris@16: { Chris@16: const charT* pc = &c; Chris@16: return toi(pc, pc + 1, radix); Chris@16: } Chris@16: locale_type imbue(locale_type l) Chris@16: { Chris@16: std::locale result(getloc()); Chris@16: m_pimpl = re_detail::create_cpp_regex_traits(l); Chris@16: return result; Chris@16: } Chris@16: locale_type getloc()const Chris@16: { Chris@16: return m_pimpl->m_locale; Chris@16: } Chris@16: std::string error_string(regex_constants::error_type n) const Chris@16: { Chris@16: return m_pimpl->error_string(n); Chris@16: } Chris@16: Chris@16: // Chris@16: // extension: Chris@16: // set the name of the message catalog in use (defaults to "boost_regex"). Chris@16: // Chris@16: static std::string catalog_name(const std::string& name); Chris@16: static std::string get_catalog_name(); Chris@16: Chris@16: private: Chris@16: boost::shared_ptr > m_pimpl; Chris@16: // Chris@16: // catalog name handler: Chris@16: // Chris@16: static std::string& get_catalog_name_inst(); Chris@16: Chris@16: #ifdef BOOST_HAS_THREADS Chris@16: static static_mutex& get_mutex_inst(); Chris@16: #endif Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: int cpp_regex_traits::toi(const charT*& first, const charT* last, int radix)const Chris@16: { Chris@16: re_detail::parser_buf sbuf; // buffer for parsing numbers. Chris@16: std::basic_istream is(&sbuf); // stream for parsing numbers. Chris@16: Chris@16: // we do NOT want to parse any thousands separators inside the stream: Chris@16: last = std::find(first, last, BOOST_USE_FACET(std::numpunct, is.getloc()).thousands_sep()); Chris@16: Chris@16: sbuf.pubsetbuf(const_cast(static_cast(first)), static_cast(last-first)); Chris@16: is.clear(); Chris@16: if(std::abs(radix) == 16) is >> std::hex; Chris@16: else if(std::abs(radix) == 8) is >> std::oct; Chris@16: else is >> std::dec; Chris@16: int val; Chris@16: if(is >> val) Chris@16: { Chris@16: first = first + ((last - first) - sbuf.in_avail()); Chris@16: return val; Chris@16: } Chris@16: else Chris@16: return -1; Chris@16: } Chris@16: Chris@16: template Chris@16: std::string cpp_regex_traits::catalog_name(const std::string& name) Chris@16: { Chris@16: #ifdef BOOST_HAS_THREADS Chris@16: static_mutex::scoped_lock lk(get_mutex_inst()); Chris@16: #endif Chris@16: std::string result(get_catalog_name_inst()); Chris@16: get_catalog_name_inst() = name; Chris@16: return result; Chris@16: } Chris@16: Chris@16: template Chris@16: std::string& cpp_regex_traits::get_catalog_name_inst() Chris@16: { Chris@16: static std::string s_name; Chris@16: return s_name; Chris@16: } Chris@16: Chris@16: template Chris@16: std::string cpp_regex_traits::get_catalog_name() Chris@16: { Chris@16: #ifdef BOOST_HAS_THREADS Chris@16: static_mutex::scoped_lock lk(get_mutex_inst()); Chris@16: #endif Chris@16: std::string result(get_catalog_name_inst()); Chris@16: return result; Chris@16: } Chris@16: Chris@16: #ifdef BOOST_HAS_THREADS Chris@16: template Chris@16: static_mutex& cpp_regex_traits::get_mutex_inst() Chris@16: { Chris@16: static static_mutex s_mutex = BOOST_STATIC_MUTEX_INIT; Chris@16: return s_mutex; Chris@16: } Chris@16: #endif Chris@16: Chris@16: Chris@16: } // boost Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable: 4103) Chris@16: #endif Chris@16: #ifdef BOOST_HAS_ABI_HEADERS Chris@16: # include BOOST_ABI_SUFFIX Chris@16: #endif Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: #endif Chris@16: Chris@16: #endif Chris@16: Chris@16: