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)
13 * LOCATION: see http://www.boost.org for most recent version.
14 * FILE w32_regex_traits.hpp
15 * VERSION see <boost/version.hpp>
16 * DESCRIPTION: Declares regular expression traits class w32_regex_traits.
19 #ifndef BOOST_W32_REGEX_TRAITS_HPP_INCLUDED
20 #define BOOST_W32_REGEX_TRAITS_HPP_INCLUDED
22 #ifndef BOOST_REGEX_NO_WIN32_LOCALE
24 #include <boost/regex/pattern_except.hpp>
25 #include <boost/regex/v5/regex_traits_defaults.hpp>
26 #ifdef BOOST_HAS_THREADS
29 #include <boost/regex/v5/primary_transform.hpp>
30 #include <boost/regex/v5/object_cache.hpp>
32 #if defined(_MSC_VER) && !defined(_WIN32_WCE) && !defined(UNDER_CE)
33 #pragma comment(lib, "user32.lib")
36 #ifdef BOOST_REGEX_MSVC
38 #pragma warning(disable:4786)
39 #if BOOST_REGEX_MSVC < 1910
40 #pragma warning(disable:4800)
46 // windows.h not included, so lets forward declare what we need:
55 #define BOOST_RE_DETAIL_DECLARE_HANDLE(x) struct x##__; typedef struct x##__ *x
57 #define BOOST_RE_DETAIL_DECLARE_HANDLE(x) typedef void* x
60 // This must be in the global namespace:
64 BOOST_RE_DETAIL_DECLARE_HANDLE(HINSTANCE);
65 typedef HINSTANCE HMODULE;
72 // forward declaration is needed by some compilers:
74 template <class charT>
75 class w32_regex_traits;
77 namespace BOOST_REGEX_DETAIL_NS{
80 // start by typedeffing the types we'll need:
82 typedef unsigned long lcid_type; // placeholder for LCID.
83 typedef std::shared_ptr<void> cat_type; // placeholder for dll HANDLE.
86 // then add wrappers around the actual Win32 API's (ie implementation hiding):
88 lcid_type w32_get_default_locale();
89 bool w32_is_lower(char, lcid_type);
90 #ifndef BOOST_NO_WREGEX
91 bool w32_is_lower(wchar_t, lcid_type);
93 bool w32_is_upper(char, lcid_type);
94 #ifndef BOOST_NO_WREGEX
95 bool w32_is_upper(wchar_t, lcid_type);
97 cat_type w32_cat_open(const std::string& name);
98 std::string w32_cat_get(const cat_type& cat, lcid_type state_id, int i, const std::string& def);
99 #ifndef BOOST_NO_WREGEX
100 std::wstring w32_cat_get(const cat_type& cat, lcid_type state_id, int i, const std::wstring& def);
102 std::string w32_transform(lcid_type state_id, const char* p1, const char* p2);
103 #ifndef BOOST_NO_WREGEX
104 std::wstring w32_transform(lcid_type state_id, const wchar_t* p1, const wchar_t* p2);
106 char w32_tolower(char c, lcid_type);
107 #ifndef BOOST_NO_WREGEX
108 wchar_t w32_tolower(wchar_t c, lcid_type);
110 char w32_toupper(char c, lcid_type);
111 #ifndef BOOST_NO_WREGEX
112 wchar_t w32_toupper(wchar_t c, lcid_type);
114 bool w32_is(lcid_type, std::uint32_t mask, char c);
115 #ifndef BOOST_NO_WREGEX
116 bool w32_is(lcid_type, std::uint32_t mask, wchar_t c);
121 // Forward declarations of the small number of windows types and API's we use:
124 #if !defined(__LP64__)
125 using dword = unsigned long;
127 using DWORD = unsigned int;
129 using word = unsigned short;
130 using lctype = dword;
132 static constexpr dword ct_ctype1 = 0x00000001;
133 static constexpr dword c1_upper = 0x0001; // upper case
134 static constexpr dword c1_lower = 0x0002; // lower case
135 static constexpr dword c1_digit = 0x0004; // decimal digits
136 static constexpr dword c1_space = 0x0008; // spacing characters
137 static constexpr dword c1_punct = 0x0010; // punctuation characters
138 static constexpr dword c1_cntrl = 0x0020; // control characters
139 static constexpr dword c1_blank = 0x0040; // blank characters
140 static constexpr dword c1_xdigit = 0x0080; // other digits
141 static constexpr dword c1_alpha = 0x0100; // any linguistic character
142 static constexpr dword c1_defined = 0x0200; // defined character
143 static constexpr unsigned int cp_acp = 0;
144 static constexpr dword lcmap_lowercase = 0x00000100;
145 static constexpr dword lcmap_uppercase = 0x00000200;
146 static constexpr dword lcmap_sortkey = 0x00000400; // WC sort key (normalize)
147 static constexpr lctype locale_idefaultansicodepage = 0x00001004;
151 # ifndef _WIN32_WCE_EMULATION
152 # define BOOST_RE_STDCALL __cdecl // Note this doesn't match the desktop definition
154 # define BOOST_RE_STDCALL __stdcall
158 # if defined(_M_IX86) || defined(__i386__)
159 # define BOOST_RE_STDCALL __stdcall
161 // On architectures other than 32-bit x86 __stdcall is ignored. Clang also issues a warning.
162 # define BOOST_RE_STDCALL
166 #if defined (WIN32_PLATFORM_PSPC)
167 #define BOOST_RE_IMPORT __declspec( dllimport )
168 #elif defined (_WIN32_WCE)
169 #define BOOST_RE_IMPORT
171 #define BOOST_RE_IMPORT __declspec( dllimport )
176 BOOST_RE_IMPORT int BOOST_RE_STDCALL FreeLibrary(HMODULE hLibModule);
177 BOOST_RE_IMPORT int BOOST_RE_STDCALL LCMapStringA(lcid_type Locale, dword dwMapFlags, const char* lpSrcStr, int cchSrc, char* lpDestStr, int cchDest);
178 BOOST_RE_IMPORT int BOOST_RE_STDCALL LCMapStringW(lcid_type Locale, dword dwMapFlags, const wchar_t* lpSrcStr, int cchSrc, wchar_t* lpDestStr, int cchDest);
179 BOOST_RE_IMPORT int BOOST_RE_STDCALL MultiByteToWideChar(unsigned int CodePage, dword dwFlags, const char* lpMultiByteStr, int cbMultiByte, wchar_t* lpWideCharStr, int cchWideChar);
180 BOOST_RE_IMPORT int BOOST_RE_STDCALL LCMapStringW(lcid_type Locale, dword dwMapFlags, const wchar_t* lpSrcStr, int cchSrc, wchar_t* lpDestStr, int cchDest);
181 BOOST_RE_IMPORT int BOOST_RE_STDCALL WideCharToMultiByte(unsigned int CodePage, dword dwFlags, const wchar_t* lpWideCharStr, int cchWideChar, char* lpMultiByteStr, int cbMultiByte, const char* lpDefaultChar, int* lpUsedDefaultChar);
182 BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExA(lcid_type Locale, dword dwInfoType, const char* lpSrcStr, int cchSrc, word* lpCharType);
183 BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExW(lcid_type Locale, dword dwInfoType, const wchar_t* lpSrcStr, int cchSrc, word* lpCharType);
184 BOOST_RE_IMPORT lcid_type BOOST_RE_STDCALL GetUserDefaultLCID();
185 BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExA(lcid_type Locale, dword dwInfoType, const char* lpSrcStr, int cchSrc, word* lpCharType);
186 BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExW(lcid_type Locale, dword dwInfoType, const wchar_t* lpSrcStr, int cchSrc, word* lpCharType);
187 BOOST_RE_IMPORT HMODULE BOOST_RE_STDCALL LoadLibraryA(const char* lpLibFileName);
188 BOOST_RE_IMPORT HMODULE BOOST_RE_STDCALL LoadLibraryW(const wchar_t* lpLibFileName);
189 BOOST_RE_IMPORT int BOOST_RE_STDCALL LoadStringW(HINSTANCE hInstance, unsigned int uID, wchar_t* lpBuffer, int cchBufferMax);
190 BOOST_RE_IMPORT int BOOST_RE_STDCALL LoadStringA(HINSTANCE hInstance, unsigned int uID, char* lpBuffer, int cchBufferMax);
191 BOOST_RE_IMPORT int BOOST_RE_STDCALL GetLocaleInfoW(lcid_type Locale, lctype LCType, wchar_t* lpLCData, int cchData);
196 // We have windows.h already included:
200 using lctype = LCTYPE;
202 static constexpr dword ct_ctype1 = 0x00000001;
203 static constexpr dword c1_upper = 0x0001; // upper case
204 static constexpr dword c1_lower = 0x0002; // lower case
205 static constexpr dword c1_digit = 0x0004; // decimal digits
206 static constexpr dword c1_space = 0x0008; // spacing characters
207 static constexpr dword c1_punct = 0x0010; // punctuation characters
208 static constexpr dword c1_cntrl = 0x0020; // control characters
209 static constexpr dword c1_blank = 0x0040; // blank characters
210 static constexpr dword c1_xdigit = 0x0080; // other digits
211 static constexpr dword c1_alpha = 0x0100; // any linguistic character
212 static constexpr dword c1_defined = 0x0200; // defined character
213 static constexpr unsigned int cp_acp = 0;
214 static constexpr dword lcmap_lowercase = 0x00000100;
215 static constexpr dword lcmap_uppercase = 0x00000200;
216 static constexpr dword lcmap_sortkey = 0x00000400; // WC sort key (normalize)
217 static constexpr lctype locale_idefaultansicodepage = 0x00001004;
220 using ::LCMapStringA;
221 using ::LCMapStringW;
222 using ::MultiByteToWideChar;
223 using ::LCMapStringW;
224 using ::WideCharToMultiByte;
225 using ::GetStringTypeExA;
226 using ::GetStringTypeExW;
227 using ::GetUserDefaultLCID;
228 using ::GetStringTypeExA;
229 using ::GetStringTypeExW;
230 using ::LoadLibraryA;
231 using ::LoadLibraryW;
234 using ::GetLocaleInfoW;
238 // class w32_regex_traits_base:
239 // acts as a container for locale and the facets we are using.
241 template <class charT>
242 struct w32_regex_traits_base
244 w32_regex_traits_base(lcid_type l)
246 lcid_type imbue(lcid_type l);
251 template <class charT>
252 inline lcid_type w32_regex_traits_base<charT>::imbue(lcid_type l)
254 lcid_type result(m_locale);
260 // class w32_regex_traits_char_layer:
261 // implements methods that require specialisation for narrow characters:
263 template <class charT>
264 class w32_regex_traits_char_layer : public w32_regex_traits_base<charT>
266 typedef std::basic_string<charT> string_type;
267 typedef std::map<charT, regex_constants::syntax_type> map_type;
268 typedef typename map_type::const_iterator map_iterator_type;
270 w32_regex_traits_char_layer(const lcid_type l);
272 regex_constants::syntax_type syntax_type(charT c)const
274 map_iterator_type i = m_char_map.find(c);
275 return ((i == m_char_map.end()) ? 0 : i->second);
277 regex_constants::escape_syntax_type escape_syntax_type(charT c) const
279 map_iterator_type i = m_char_map.find(c);
280 if(i == m_char_map.end())
282 if(::boost::BOOST_REGEX_DETAIL_NS::w32_is_lower(c, this->m_locale)) return regex_constants::escape_type_class;
283 if(::boost::BOOST_REGEX_DETAIL_NS::w32_is_upper(c, this->m_locale)) return regex_constants::escape_type_not_class;
288 charT tolower(charT c)const
290 return ::boost::BOOST_REGEX_DETAIL_NS::w32_tolower(c, this->m_locale);
292 bool isctype(std::uint32_t mask, charT c)const
294 return ::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, mask, c);
298 string_type get_default_message(regex_constants::syntax_type);
299 // TODO: use a hash table when available!
303 template <class charT>
304 w32_regex_traits_char_layer<charT>::w32_regex_traits_char_layer(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)
305 : w32_regex_traits_base<charT>(l)
307 // we need to start by initialising our syntax map so we know which
308 // character is used for which purpose:
310 std::string cat_name(w32_regex_traits<charT>::get_catalog_name());
313 cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name);
316 std::string m("Unable to open message catalog: ");
317 std::runtime_error err(m + cat_name);
318 boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err);
322 // if we have a valid catalog then load our messages:
326 for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
328 string_type mss = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i, get_default_message(i));
329 for(typename string_type::size_type j = 0; j < mss.size(); ++j)
331 this->m_char_map[mss[j]] = i;
337 for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
339 const char* ptr = get_default_syntax(i);
342 this->m_char_map[static_cast<charT>(*ptr)] = i;
349 template <class charT>
350 typename w32_regex_traits_char_layer<charT>::string_type
351 w32_regex_traits_char_layer<charT>::get_default_message(regex_constants::syntax_type i)
353 const char* ptr = get_default_syntax(i);
357 result.append(1, static_cast<charT>(*ptr));
364 // specialised version for narrow characters:
367 class w32_regex_traits_char_layer<char> : public w32_regex_traits_base<char>
369 typedef std::string string_type;
371 w32_regex_traits_char_layer(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)
372 : w32_regex_traits_base<char>(l)
377 regex_constants::syntax_type syntax_type(char c)const
379 return m_char_map[static_cast<unsigned char>(c)];
381 regex_constants::escape_syntax_type escape_syntax_type(char c) const
383 return m_char_map[static_cast<unsigned char>(c)];
385 char tolower(char c)const
387 return m_lower_map[static_cast<unsigned char>(c)];
389 bool isctype(std::uint32_t mask, char c)const
391 return m_type_map[static_cast<unsigned char>(c)] & mask;
395 regex_constants::syntax_type m_char_map[1u << CHAR_BIT];
396 char m_lower_map[1u << CHAR_BIT];
397 std::uint16_t m_type_map[1u << CHAR_BIT];
403 // class w32_regex_traits_implementation:
404 // provides pimpl implementation for w32_regex_traits.
406 template <class charT>
407 class w32_regex_traits_implementation : public w32_regex_traits_char_layer<charT>
410 typedef typename w32_regex_traits<charT>::char_class_type char_class_type;
411 static const char_class_type mask_word = 0x0400; // must be C1_DEFINED << 1
412 static const char_class_type mask_unicode = 0x0800; // must be C1_DEFINED << 2
413 static const char_class_type mask_horizontal = 0x1000; // must be C1_DEFINED << 3
414 static const char_class_type mask_vertical = 0x2000; // must be C1_DEFINED << 4
415 static const char_class_type mask_base = 0x3ff; // all the masks used by the CT_CTYPE1 group
417 typedef std::basic_string<charT> string_type;
418 typedef charT char_type;
419 w32_regex_traits_implementation(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l);
420 std::string error_string(regex_constants::error_type n) const
422 if(!m_error_strings.empty())
424 std::map<int, std::string>::const_iterator p = m_error_strings.find(n);
425 return (p == m_error_strings.end()) ? std::string(get_default_error_string(n)) : p->second;
427 return get_default_error_string(n);
429 char_class_type lookup_classname(const charT* p1, const charT* p2) const
431 char_class_type result = lookup_classname_imp(p1, p2);
434 typedef typename string_type::size_type size_type;
435 string_type temp(p1, p2);
436 for(size_type i = 0; i < temp.size(); ++i)
437 temp[i] = this->tolower(temp[i]);
438 result = lookup_classname_imp(&*temp.begin(), &*temp.begin() + temp.size());
442 string_type lookup_collatename(const charT* p1, const charT* p2) const;
443 string_type transform_primary(const charT* p1, const charT* p2) const;
444 string_type transform(const charT* p1, const charT* p2) const
446 return ::boost::BOOST_REGEX_DETAIL_NS::w32_transform(this->m_locale, p1, p2);
449 std::map<int, std::string> m_error_strings; // error messages indexed by numberic ID
450 std::map<string_type, char_class_type> m_custom_class_names; // character class names
451 std::map<string_type, string_type> m_custom_collate_names; // collating element names
452 unsigned m_collate_type; // the form of the collation string
453 charT m_collate_delim; // the collation group delimiter
457 char_class_type lookup_classname_imp(const charT* p1, const charT* p2) const;
460 template <class charT>
461 typename w32_regex_traits_implementation<charT>::string_type
462 w32_regex_traits_implementation<charT>::transform_primary(const charT* p1, const charT* p2) const
466 // What we do here depends upon the format of the sort key returned by
467 // sort key returned by this->transform:
469 switch(m_collate_type)
473 // the best we can do is translate to lower case, then get a regular sort key:
475 result.assign(p1, p2);
476 typedef typename string_type::size_type size_type;
477 for(size_type i = 0; i < result.size(); ++i)
478 result[i] = this->tolower(result[i]);
479 result = this->transform(&*result.begin(), &*result.begin() + result.size());
484 // get a regular sort key, and then truncate it:
485 result.assign(this->transform(p1, p2));
486 result.erase(this->m_collate_delim);
490 // get a regular sort key, and then truncate everything after the delim:
491 result.assign(this->transform(p1, p2));
493 for(i = 0; i < result.size(); ++i)
495 if(result[i] == m_collate_delim)
502 result = string_type(1, charT(0));
506 template <class charT>
507 typename w32_regex_traits_implementation<charT>::string_type
508 w32_regex_traits_implementation<charT>::lookup_collatename(const charT* p1, const charT* p2) const
510 typedef typename std::map<string_type, string_type>::const_iterator iter_type;
511 if(m_custom_collate_names.size())
513 iter_type pos = m_custom_collate_names.find(string_type(p1, p2));
514 if(pos != m_custom_collate_names.end())
517 std::string name(p1, p2);
518 name = lookup_default_collate_name(name);
520 return string_type(name.begin(), name.end());
522 return string_type(1, *p1);
523 return string_type();
526 template <class charT>
527 w32_regex_traits_implementation<charT>::w32_regex_traits_implementation(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)
528 : w32_regex_traits_char_layer<charT>(l)
531 std::string cat_name(w32_regex_traits<charT>::get_catalog_name());
534 cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name);
537 std::string m("Unable to open message catalog: ");
538 std::runtime_error err(m + cat_name);
539 boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err);
543 // if we have a valid catalog then load our messages:
550 for(boost::regex_constants::error_type i = static_cast<boost::regex_constants::error_type>(0);
551 i <= boost::regex_constants::error_unknown;
552 i = static_cast<boost::regex_constants::error_type>(i + 1))
554 const char* p = get_default_error_string(i);
555 string_type default_message;
558 default_message.append(1, static_cast<charT>(*p));
561 string_type s = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i+200, default_message);
563 for(std::string::size_type j = 0; j < s.size(); ++j)
565 result.append(1, static_cast<char>(s[j]));
567 m_error_strings[i] = result;
570 // Custom class names:
572 static const char_class_type masks[14] =
574 0x0104u, // C1_ALPHA | C1_DIGIT
578 (~(0x0020u|0x0008u) & 0x01ffu) | 0x0400u, // not C1_CNTRL or C1_SPACE
580 (~0x0020u & 0x01ffu) | 0x0400, // not C1_CNTRL
584 0x0080u, // C1_XDIGIT
586 w32_regex_traits_implementation<charT>::mask_word,
587 w32_regex_traits_implementation<charT>::mask_unicode,
589 static const string_type null_string;
590 for(unsigned int j = 0; j <= 13; ++j)
592 string_type s(::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, j+300, null_string));
594 this->m_custom_class_names[s] = masks[j];
598 // get the collation format used by m_pcollate:
600 m_collate_type = BOOST_REGEX_DETAIL_NS::find_sort_syntax(this, &m_collate_delim);
603 template <class charT>
604 typename w32_regex_traits_implementation<charT>::char_class_type
605 w32_regex_traits_implementation<charT>::lookup_classname_imp(const charT* p1, const charT* p2) const
607 static const char_class_type masks[22] =
610 0x0104u, // C1_ALPHA | C1_DIGIT
616 (~(0x0020u|0x0008u|0x0040) & 0x01ffu) | 0x0400u, // not C1_CNTRL or C1_SPACE or C1_BLANK
617 w32_regex_traits_implementation<charT>::mask_horizontal,
620 (~0x0020u & 0x01ffu) | 0x0400, // not C1_CNTRL
625 w32_regex_traits_implementation<charT>::mask_unicode,
627 w32_regex_traits_implementation<charT>::mask_vertical,
628 0x0104u | w32_regex_traits_implementation<charT>::mask_word,
629 0x0104u | w32_regex_traits_implementation<charT>::mask_word,
630 0x0080u, // C1_XDIGIT
632 if(m_custom_class_names.size())
634 typedef typename std::map<std::basic_string<charT>, char_class_type>::const_iterator map_iter;
635 map_iter pos = m_custom_class_names.find(string_type(p1, p2));
636 if(pos != m_custom_class_names.end())
639 std::size_t state_id = 1u + (std::size_t)BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2);
640 if(state_id < sizeof(masks) / sizeof(masks[0]))
641 return masks[state_id];
646 template <class charT>
647 std::shared_ptr<const w32_regex_traits_implementation<charT> > create_w32_regex_traits(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)
649 // TODO: create a cache for previously constructed objects.
650 return boost::object_cache< ::boost::BOOST_REGEX_DETAIL_NS::lcid_type, w32_regex_traits_implementation<charT> >::get(l, 5);
653 } // BOOST_REGEX_DETAIL_NS
655 template <class charT>
656 class w32_regex_traits
659 typedef charT char_type;
660 typedef std::size_t size_type;
661 typedef std::basic_string<char_type> string_type;
662 typedef ::boost::BOOST_REGEX_DETAIL_NS::lcid_type locale_type;
663 typedef std::uint_least32_t char_class_type;
665 struct boost_extensions_tag{};
668 : m_pimpl(BOOST_REGEX_DETAIL_NS::create_w32_regex_traits<charT>(::boost::BOOST_REGEX_DETAIL_NS::w32_get_default_locale()))
670 static size_type length(const char_type* p)
672 return std::char_traits<charT>::length(p);
674 regex_constants::syntax_type syntax_type(charT c)const
676 return m_pimpl->syntax_type(c);
678 regex_constants::escape_syntax_type escape_syntax_type(charT c) const
680 return m_pimpl->escape_syntax_type(c);
682 charT translate(charT c) const
686 charT translate_nocase(charT c) const
688 return this->m_pimpl->tolower(c);
690 charT translate(charT c, bool icase) const
692 return icase ? this->m_pimpl->tolower(c) : c;
694 charT tolower(charT c) const
696 return this->m_pimpl->tolower(c);
698 charT toupper(charT c) const
700 return ::boost::BOOST_REGEX_DETAIL_NS::w32_toupper(c, this->m_pimpl->m_locale);
702 string_type transform(const charT* p1, const charT* p2) const
704 return ::boost::BOOST_REGEX_DETAIL_NS::w32_transform(this->m_pimpl->m_locale, p1, p2);
706 string_type transform_primary(const charT* p1, const charT* p2) const
708 return m_pimpl->transform_primary(p1, p2);
710 char_class_type lookup_classname(const charT* p1, const charT* p2) const
712 return m_pimpl->lookup_classname(p1, p2);
714 string_type lookup_collatename(const charT* p1, const charT* p2) const
716 return m_pimpl->lookup_collatename(p1, p2);
718 bool isctype(charT c, char_class_type f) const
720 if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_base)
721 && (this->m_pimpl->isctype(f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_base, c)))
723 else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_unicode) && BOOST_REGEX_DETAIL_NS::is_extended(c))
725 else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_word) && (c == '_'))
727 else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_vertical)
728 && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == '\v')))
730 else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_horizontal)
731 && this->isctype(c, 0x0008u) && !this->isctype(c, BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_vertical))
735 std::intmax_t toi(const charT*& p1, const charT* p2, int radix)const
737 return ::boost::BOOST_REGEX_DETAIL_NS::global_toi(p1, p2, radix, *this);
739 int value(charT c, int radix)const
741 int result = (int)::boost::BOOST_REGEX_DETAIL_NS::global_value(c);
742 return result < radix ? result : -1;
744 locale_type imbue(locale_type l)
746 ::boost::BOOST_REGEX_DETAIL_NS::lcid_type result(getloc());
747 m_pimpl = BOOST_REGEX_DETAIL_NS::create_w32_regex_traits<charT>(l);
750 locale_type getloc()const
752 return m_pimpl->m_locale;
754 std::string error_string(regex_constants::error_type n) const
756 return m_pimpl->error_string(n);
761 // set the name of the message catalog in use (defaults to "boost_regex").
763 static std::string catalog_name(const std::string& name);
764 static std::string get_catalog_name();
767 std::shared_ptr<const BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT> > m_pimpl;
769 // catalog name handler:
771 static std::string& get_catalog_name_inst();
773 #ifdef BOOST_HAS_THREADS
774 static std::mutex& get_mutex_inst();
778 template <class charT>
779 std::string w32_regex_traits<charT>::catalog_name(const std::string& name)
781 #ifdef BOOST_HAS_THREADS
782 std::lock_guard<std::mutex> lk(get_mutex_inst());
784 std::string result(get_catalog_name_inst());
785 get_catalog_name_inst() = name;
789 template <class charT>
790 std::string& w32_regex_traits<charT>::get_catalog_name_inst()
792 static std::string s_name;
796 template <class charT>
797 std::string w32_regex_traits<charT>::get_catalog_name()
799 #ifdef BOOST_HAS_THREADS
800 std::lock_guard<std::mutex> lk(get_mutex_inst());
802 std::string result(get_catalog_name_inst());
806 #ifdef BOOST_HAS_THREADS
807 template <class charT>
808 std::mutex& w32_regex_traits<charT>::get_mutex_inst()
810 static std::mutex s_mutex;
815 namespace BOOST_REGEX_DETAIL_NS {
817 #ifdef BOOST_NO_ANSI_APIS
818 inline unsigned int get_code_page_for_locale_id(lcid_type idx)
820 wchar_t code_page_string[7];
821 if (boost::BOOST_REGEX_DETAIL_NS::GetLocaleInfoW(idx, locale_idefaultansicodepage, code_page_string, 7) == 0)
824 return static_cast<unsigned int>(_wtol(code_page_string));
829 inline void w32_regex_traits_char_layer<char>::init()
831 // we need to start by initialising our syntax map so we know which
832 // character is used for which purpose:
833 std::memset(m_char_map, 0, sizeof(m_char_map));
835 std::string cat_name(w32_regex_traits<char>::get_catalog_name());
838 cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name);
841 std::string m("Unable to open message catalog: ");
842 std::runtime_error err(m + cat_name);
843 ::boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err);
847 // if we have a valid catalog then load our messages:
851 for (regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
853 string_type mss = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i, get_default_syntax(i));
854 for (string_type::size_type j = 0; j < mss.size(); ++j)
856 m_char_map[static_cast<unsigned char>(mss[j])] = i;
862 for (regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
864 const char* ptr = get_default_syntax(i);
867 m_char_map[static_cast<unsigned char>(*ptr)] = i;
873 // finish off by calculating our escape types:
875 unsigned char i = 'A';
878 if (m_char_map[i] == 0)
880 if (::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, 0x0002u, (char)i))
881 m_char_map[i] = regex_constants::escape_type_class;
882 else if (::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, 0x0001u, (char)i))
883 m_char_map[i] = regex_constants::escape_type_not_class;
885 } while (0xFF != i++);
888 // fill in lower case map:
890 char char_map[1 << CHAR_BIT];
891 for (int ii = 0; ii < (1 << CHAR_BIT); ++ii)
892 char_map[ii] = static_cast<char>(ii);
893 #ifndef BOOST_NO_ANSI_APIS
894 int r = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA(this->m_locale, lcmap_lowercase, char_map, 1 << CHAR_BIT, this->m_lower_map, 1 << CHAR_BIT);
895 BOOST_REGEX_ASSERT(r != 0);
897 unsigned int code_page = get_code_page_for_locale_id(this->m_locale);
898 BOOST_REGEX_ASSERT(code_page != 0);
900 wchar_t wide_char_map[1 << CHAR_BIT];
901 int conv_r = boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, char_map, 1 << CHAR_BIT, wide_char_map, 1 << CHAR_BIT);
902 BOOST_REGEX_ASSERT(conv_r != 0);
904 wchar_t wide_lower_map[1 << CHAR_BIT];
905 int r = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(this->m_locale, lcmap_lowercase, wide_char_map, 1 << CHAR_BIT, wide_lower_map, 1 << CHAR_BIT);
906 BOOST_REGEX_ASSERT(r != 0);
908 conv_r = boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(code_page, 0, wide_lower_map, r, this->m_lower_map, 1 << CHAR_BIT, NULL, NULL);
909 BOOST_REGEX_ASSERT(conv_r != 0);
911 if (r < (1 << CHAR_BIT))
913 // if we have multibyte characters then not all may have been given
914 // a lower case mapping:
915 for (int jj = r; jj < (1 << CHAR_BIT); ++jj)
916 this->m_lower_map[jj] = static_cast<char>(jj);
919 #ifndef BOOST_NO_ANSI_APIS
920 r = boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(this->m_locale, ct_ctype1, char_map, 1 << CHAR_BIT, this->m_type_map);
922 r = boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(this->m_locale, ct_ctype1, wide_char_map, 1 << CHAR_BIT, this->m_type_map);
924 BOOST_REGEX_ASSERT(0 != r);
927 inline lcid_type w32_get_default_locale()
929 return boost::BOOST_REGEX_DETAIL_NS::GetUserDefaultLCID();
932 inline bool w32_is_lower(char c, lcid_type idx)
934 #ifndef BOOST_NO_ANSI_APIS
936 if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_lower))
940 unsigned int code_page = get_code_page_for_locale_id(idx);
945 if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0)
949 if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &wide_c, 1, &mask) && (mask & c1_lower))
955 inline bool w32_is_lower(wchar_t c, lcid_type idx)
958 if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_lower))
963 inline bool w32_is_upper(char c, lcid_type idx)
965 #ifndef BOOST_NO_ANSI_APIS
967 if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_upper))
971 unsigned int code_page = get_code_page_for_locale_id(idx);
976 if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0)
980 if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &wide_c, 1, &mask) && (mask & c1_upper))
986 inline bool w32_is_upper(wchar_t c, lcid_type idx)
989 if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_upper))
994 inline void free_module(void* mod)
996 boost::BOOST_REGEX_DETAIL_NS::FreeLibrary(static_cast<HMODULE>(mod));
999 inline cat_type w32_cat_open(const std::string& name)
1001 #ifndef BOOST_NO_ANSI_APIS
1002 cat_type result(boost::BOOST_REGEX_DETAIL_NS::LoadLibraryA(name.c_str()), &free_module);
1005 wchar_t* wide_name = (wchar_t*)_alloca((name.size() + 1) * sizeof(wchar_t));
1006 if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(cp_acp, 0, name.c_str(), (int)name.size(), wide_name, (int)(name.size() + 1)) == 0)
1009 cat_type result(boost::BOOST_REGEX_DETAIL_NS::LoadLibraryW(wide_name), &free_module);
1014 inline std::string w32_cat_get(const cat_type& cat, lcid_type, int i, const std::string& def)
1016 #ifndef BOOST_NO_ANSI_APIS
1018 if (0 == boost::BOOST_REGEX_DETAIL_NS::LoadStringA(
1019 static_cast<HMODULE>(cat.get()),
1029 int r = boost::BOOST_REGEX_DETAIL_NS::LoadStringW(
1030 static_cast<HMODULE>(cat.get()),
1039 int buf_size = 1 + boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(cp_acp, 0, wbuf, r, NULL, 0, NULL, NULL);
1040 char* buf = (char*)_alloca(buf_size);
1041 if (boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(cp_acp, 0, wbuf, r, buf, buf_size, NULL, NULL) == 0)
1042 return def; // failed conversion.
1044 return std::string(buf);
1047 #ifndef BOOST_NO_WREGEX
1048 inline std::wstring w32_cat_get(const cat_type& cat, lcid_type, int i, const std::wstring& def)
1051 if (0 == boost::BOOST_REGEX_DETAIL_NS::LoadStringW(static_cast<HMODULE>(cat.get()), i, buf, 256))
1055 return std::wstring(buf);
1058 inline std::string w32_transform(lcid_type idx, const char* p1, const char* p2)
1060 #ifndef BOOST_NO_ANSI_APIS
1061 int bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA(
1062 idx, // locale identifier
1063 lcmap_sortkey, // mapping transformation type
1064 p1, // source string
1065 static_cast<int>(p2 - p1), // number of characters in source string
1066 0, // destination buffer
1067 0 // size of destination buffer
1070 return std::string(p1, p2);
1071 std::string result(++bytes, '\0');
1072 bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA(
1073 idx, // locale identifier
1074 lcmap_sortkey, // mapping transformation type
1075 p1, // source string
1076 static_cast<int>(p2 - p1), // number of characters in source string
1077 &*result.begin(), // destination buffer
1078 bytes // size of destination buffer
1081 unsigned int code_page = get_code_page_for_locale_id(idx);
1083 return std::string(p1, p2);
1085 int src_len = static_cast<int>(p2 - p1);
1086 wchar_t* wide_p1 = (wchar_t*)_alloca((src_len + 1) * 2);
1087 if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, p1, src_len, wide_p1, src_len + 1) == 0)
1088 return std::string(p1, p2);
1090 int bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1091 idx, // locale identifier
1092 lcmap_sortkey, // mapping transformation type
1093 wide_p1, // source string
1094 src_len, // number of characters in source string
1095 0, // destination buffer
1096 0 // size of destination buffer
1099 return std::string(p1, p2);
1100 std::string result(++bytes, '\0');
1101 bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1102 idx, // locale identifier
1103 lcmap_sortkey, // mapping transformation type
1104 wide_p1, // source string
1105 src_len, // number of characters in source string
1106 (wchar_t*) & *result.begin(), // destination buffer
1107 bytes // size of destination buffer
1110 if (bytes > static_cast<int>(result.size()))
1111 return std::string(p1, p2);
1112 while (result.size() && result[result.size() - 1] == '\0')
1114 result.erase(result.size() - 1);
1119 #ifndef BOOST_NO_WREGEX
1120 inline std::wstring w32_transform(lcid_type idx, const wchar_t* p1, const wchar_t* p2)
1122 int bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1123 idx, // locale identifier
1124 lcmap_sortkey, // mapping transformation type
1125 p1, // source string
1126 static_cast<int>(p2 - p1), // number of characters in source string
1127 0, // destination buffer
1128 0 // size of destination buffer
1131 return std::wstring(p1, p2);
1132 std::string result(++bytes, '\0');
1133 bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1134 idx, // locale identifier
1135 lcmap_sortkey, // mapping transformation type
1136 p1, // source string
1137 static_cast<int>(p2 - p1), // number of characters in source string
1138 reinterpret_cast<wchar_t*>(&*result.begin()), // destination buffer *of bytes*
1139 bytes // size of destination buffer
1141 if (bytes > static_cast<int>(result.size()))
1142 return std::wstring(p1, p2);
1143 while (result.size() && result[result.size() - 1] == L'\0')
1145 result.erase(result.size() - 1);
1148 for (std::string::size_type i = 0; i < result.size(); ++i)
1149 r2.append(1, static_cast<wchar_t>(static_cast<unsigned char>(result[i])));
1153 inline char w32_tolower(char c, lcid_type idx)
1156 #ifndef BOOST_NO_ANSI_APIS
1157 int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA(
1158 idx, // locale identifier
1159 lcmap_lowercase, // mapping transformation type
1160 &c, // source string
1161 1, // number of characters in source string
1162 result, // destination buffer
1163 1); // size of destination buffer
1167 unsigned int code_page = get_code_page_for_locale_id(idx);
1172 if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0)
1175 wchar_t wide_result;
1176 int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1177 idx, // locale identifier
1178 lcmap_lowercase, // mapping transformation type
1179 &wide_c, // source string
1180 1, // number of characters in source string
1181 &wide_result, // destination buffer
1182 1); // size of destination buffer
1186 if (boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(code_page, 0, &wide_result, 1, result, 2, NULL, NULL) == 0)
1187 return c; // No single byte lower case equivalent available
1192 #ifndef BOOST_NO_WREGEX
1193 inline wchar_t w32_tolower(wchar_t c, lcid_type idx)
1196 int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1197 idx, // locale identifier
1198 lcmap_lowercase, // mapping transformation type
1199 &c, // source string
1200 1, // number of characters in source string
1201 result, // destination buffer
1202 1); // size of destination buffer
1208 inline char w32_toupper(char c, lcid_type idx)
1211 #ifndef BOOST_NO_ANSI_APIS
1212 int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA(
1213 idx, // locale identifier
1214 lcmap_uppercase, // mapping transformation type
1215 &c, // source string
1216 1, // number of characters in source string
1217 result, // destination buffer
1218 1); // size of destination buffer
1222 unsigned int code_page = get_code_page_for_locale_id(idx);
1227 if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0)
1230 wchar_t wide_result;
1231 int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1232 idx, // locale identifier
1233 lcmap_uppercase, // mapping transformation type
1234 &wide_c, // source string
1235 1, // number of characters in source string
1236 &wide_result, // destination buffer
1237 1); // size of destination buffer
1241 if (boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(code_page, 0, &wide_result, 1, result, 2, NULL, NULL) == 0)
1242 return c; // No single byte upper case equivalent available.
1247 #ifndef BOOST_NO_WREGEX
1248 inline wchar_t w32_toupper(wchar_t c, lcid_type idx)
1251 int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1252 idx, // locale identifier
1253 lcmap_uppercase, // mapping transformation type
1254 &c, // source string
1255 1, // number of characters in source string
1256 result, // destination buffer
1257 1); // size of destination buffer
1263 inline bool w32_is(lcid_type idx, std::uint32_t m, char c)
1266 #ifndef BOOST_NO_ANSI_APIS
1267 if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(idx, ct_ctype1, &c, 1, &mask) && (mask & m & w32_regex_traits_implementation<char>::mask_base))
1270 unsigned int code_page = get_code_page_for_locale_id(idx);
1275 if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0)
1278 if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &wide_c, 1, &mask) && (mask & m & w32_regex_traits_implementation<char>::mask_base))
1281 if ((m & w32_regex_traits_implementation<char>::mask_word) && (c == '_'))
1286 #ifndef BOOST_NO_WREGEX
1287 inline bool w32_is(lcid_type idx, std::uint32_t m, wchar_t c)
1290 if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &c, 1, &mask) && (mask & m & w32_regex_traits_implementation<wchar_t>::mask_base))
1292 if ((m & w32_regex_traits_implementation<wchar_t>::mask_word) && (c == '_'))
1294 if ((m & w32_regex_traits_implementation<wchar_t>::mask_unicode) && (c > 0xff))
1300 } // BOOST_REGEX_DETAIL_NS
1305 #ifdef BOOST_REGEX_MSVC
1306 #pragma warning(pop)
1309 #endif // BOOST_REGEX_NO_WIN32_LOCALE