Coverage Report

Created: 2026-08-14 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boost/boost/regex/v5/c_regex_traits.hpp
Line
Count
Source
1
/*
2
 *
3
 * Copyright (c) 2004
4
 * John Maddock
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         c_regex_traits.hpp
15
  *   VERSION      see <boost/version.hpp>
16
  *   DESCRIPTION: Declares regular expression traits class that wraps the global C locale.
17
  */
18
19
#ifndef BOOST_C_REGEX_TRAITS_HPP_INCLUDED
20
#define BOOST_C_REGEX_TRAITS_HPP_INCLUDED
21
22
#ifndef BOOST_REGEX_AS_MODULE
23
#include <cctype>
24
#include <cstdint>
25
#include <cwctype>
26
#endif
27
28
#include <boost/regex/config.hpp>
29
#include <boost/regex/v5/regex_workaround.hpp>
30
#include <boost/regex/v5/primary_transform.hpp>
31
#include <boost/regex/v5/regex_traits_defaults.hpp>
32
33
namespace boost{
34
35
   namespace BOOST_REGEX_DETAIL_NS {
36
37
      enum
38
      {
39
         char_class_space = 1 << 0,
40
         char_class_print = 1 << 1,
41
         char_class_cntrl = 1 << 2,
42
         char_class_upper = 1 << 3,
43
         char_class_lower = 1 << 4,
44
         char_class_alpha = 1 << 5,
45
         char_class_digit = 1 << 6,
46
         char_class_punct = 1 << 7,
47
         char_class_xdigit = 1 << 8,
48
         char_class_alnum = char_class_alpha | char_class_digit,
49
         char_class_graph = char_class_alnum | char_class_punct,
50
         char_class_blank = 1 << 9,
51
         char_class_word = 1 << 10,
52
         char_class_unicode = 1 << 11,
53
         char_class_horizontal = 1 << 12,
54
         char_class_vertical = 1 << 13
55
      };
56
57
   }
58
59
BOOST_REGEX_MODULE_EXPORT template <class charT>
60
struct c_regex_traits;
61
62
BOOST_REGEX_MODULE_EXPORT template<>
63
struct c_regex_traits<char>
64
{
65
0
   c_regex_traits(){}
66
   typedef char char_type;
67
   typedef std::size_t size_type;
68
   typedef std::string string_type;
69
   struct locale_type{};
70
   typedef std::uint32_t char_class_type;
71
72
   static size_type length(const char_type* p) 
73
0
   { 
74
0
      return (std::strlen)(p); 
75
0
   }
76
77
   char translate(char c) const 
78
0
   { 
79
0
      return c; 
80
0
   }
81
   char translate_nocase(char c) const 
82
0
   { 
83
0
      return static_cast<char>((std::tolower)(static_cast<unsigned char>(c))); 
84
0
   }
85
86
   static string_type  transform(const char* p1, const char* p2);
87
   static string_type  transform_primary(const char* p1, const char* p2);
88
89
   static char_class_type  lookup_classname(const char* p1, const char* p2);
90
   static string_type  lookup_collatename(const char* p1, const char* p2);
91
92
   static bool  isctype(char, char_class_type);
93
   static int  value(char, int);
94
95
   locale_type imbue(locale_type l)
96
0
   { return l; }
97
   locale_type getloc()const
98
0
   { return locale_type(); }
99
100
private:
101
   // this type is not copyable:
102
   c_regex_traits(const c_regex_traits&);
103
   c_regex_traits& operator=(const c_regex_traits&);
104
};
105
106
#ifndef BOOST_NO_WREGEX
107
BOOST_REGEX_MODULE_EXPORT template<>
108
struct c_regex_traits<wchar_t>
109
{
110
0
   c_regex_traits(){}
111
   typedef wchar_t char_type;
112
   typedef std::size_t size_type;
113
   typedef std::wstring string_type;
114
   struct locale_type{};
115
   typedef std::uint32_t char_class_type;
116
117
   static size_type length(const char_type* p) 
118
0
   { 
119
0
      return (std::wcslen)(p); 
120
0
   }
121
122
   wchar_t translate(wchar_t c) const 
123
0
   { 
124
0
      return c; 
125
0
   }
126
   wchar_t translate_nocase(wchar_t c) const 
127
0
   { 
128
0
      return (std::towlower)(c); 
129
0
   }
130
131
   static string_type  transform(const wchar_t* p1, const wchar_t* p2);
132
   static string_type  transform_primary(const wchar_t* p1, const wchar_t* p2);
133
134
   static char_class_type  lookup_classname(const wchar_t* p1, const wchar_t* p2);
135
   static string_type  lookup_collatename(const wchar_t* p1, const wchar_t* p2);
136
137
   static bool  isctype(wchar_t, char_class_type);
138
   static int  value(wchar_t, int);
139
140
   locale_type imbue(locale_type l)
141
0
   { return l; }
142
   locale_type getloc()const
143
0
   { return locale_type(); }
144
145
private:
146
   // this type is not copyable:
147
   c_regex_traits(const c_regex_traits&);
148
   c_regex_traits& operator=(const c_regex_traits&);
149
};
150
151
#endif // BOOST_NO_WREGEX
152
153
inline c_regex_traits<char>::string_type  c_regex_traits<char>::transform(const char* p1, const char* p2)
154
0
{
155
0
   std::string result(10, ' ');
156
0
   std::size_t s = result.size();
157
0
   std::size_t r;
158
0
   std::string src(p1, p2);
159
0
   while (s < (r = std::strxfrm(&*result.begin(), src.c_str(), s)))
160
0
   {
161
#if defined(_CPPLIB_VER)
162
      //
163
      // A bug in VC11 and 12 causes the program to hang if we pass a null-string
164
      // to std::strxfrm, but only for certain locales :-(
165
      // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware).
166
      //
167
      if (r == INT_MAX)
168
      {
169
         result.erase();
170
         result.insert(result.begin(), static_cast<char>(0));
171
         return result;
172
      }
173
#endif
174
0
      result.append(r - s + 3, ' ');
175
0
      s = result.size();
176
0
   }
177
0
   result.erase(r);
178
0
   return result;
179
0
}
180
181
inline c_regex_traits<char>::string_type  c_regex_traits<char>::transform_primary(const char* p1, const char* p2)
182
0
{
183
0
   static char s_delim;
184
0
   static const int s_collate_type = ::boost::BOOST_REGEX_DETAIL_NS::find_sort_syntax(static_cast<c_regex_traits<char>*>(0), &s_delim);
185
0
   std::string result;
186
   //
187
   // What we do here depends upon the format of the sort key returned by
188
   // sort key returned by this->transform:
189
   //
190
0
   switch (s_collate_type)
191
0
   {
192
0
   case ::boost::BOOST_REGEX_DETAIL_NS::sort_C:
193
0
   case ::boost::BOOST_REGEX_DETAIL_NS::sort_unknown:
194
      // the best we can do is translate to lower case, then get a regular sort key:
195
0
   {
196
0
      result.assign(p1, p2);
197
0
      for (std::string::size_type i = 0; i < result.size(); ++i)
198
0
         result[i] = static_cast<char>((std::tolower)(static_cast<unsigned char>(result[i])));
199
0
      result = transform(&*result.begin(), &*result.begin() + result.size());
200
0
      break;
201
0
   }
202
0
   case ::boost::BOOST_REGEX_DETAIL_NS::sort_fixed:
203
0
   {
204
      // get a regular sort key, and then truncate it:
205
0
      result = transform(p1, p2);
206
0
      result.erase(s_delim);
207
0
      break;
208
0
   }
209
0
   case ::boost::BOOST_REGEX_DETAIL_NS::sort_delim:
210
      // get a regular sort key, and then truncate everything after the delim:
211
0
      result = transform(p1, p2);
212
0
      if ((!result.empty()) && (result[0] == s_delim))
213
0
         break;
214
0
      std::size_t i;
215
0
      for (i = 0; i < result.size(); ++i)
216
0
      {
217
0
         if (result[i] == s_delim)
218
0
            break;
219
0
      }
220
0
      result.erase(i);
221
0
      break;
222
0
   }
223
0
   if (result.empty())
224
0
      result = std::string(1, char(0));
225
0
   return result;
226
0
}
227
228
inline c_regex_traits<char>::char_class_type  c_regex_traits<char>::lookup_classname(const char* p1, const char* p2)
229
0
{
230
0
   using namespace BOOST_REGEX_DETAIL_NS;
231
0
   static const char_class_type masks[] =
232
0
   {
233
0
      0,
234
0
      char_class_alnum,
235
0
      char_class_alpha,
236
0
      char_class_blank,
237
0
      char_class_cntrl,
238
0
      char_class_digit,
239
0
      char_class_digit,
240
0
      char_class_graph,
241
0
      char_class_horizontal,
242
0
      char_class_lower,
243
0
      char_class_lower,
244
0
      char_class_print,
245
0
      char_class_punct,
246
0
      char_class_space,
247
0
      char_class_space,
248
0
      char_class_upper,
249
0
      char_class_unicode,
250
0
      char_class_upper,
251
0
      char_class_vertical,
252
0
      char_class_alnum | char_class_word,
253
0
      char_class_alnum | char_class_word,
254
0
      char_class_xdigit,
255
0
   };
256
257
0
   int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2);
258
0
   if (idx < 0)
259
0
   {
260
0
      std::string s(p1, p2);
261
0
      for (std::string::size_type i = 0; i < s.size(); ++i)
262
0
         s[i] = static_cast<char>((std::tolower)(static_cast<unsigned char>(s[i])));
263
0
      idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size());
264
0
   }
265
0
   BOOST_REGEX_ASSERT(std::size_t(idx) + 1u < sizeof(masks) / sizeof(masks[0]));
266
0
   return masks[idx + 1];
267
0
}
Unexecuted instantiation: boost::c_regex_traits<char>::lookup_classname(char const*, char const*)
Unexecuted instantiation: boost::c_regex_traits<char>::lookup_classname(char const*, char const*)
268
269
inline bool  c_regex_traits<char>::isctype(char c, char_class_type mask)
270
0
{
271
0
   using namespace BOOST_REGEX_DETAIL_NS;
272
0
   return
273
0
      ((mask & char_class_space) && (std::isspace)(static_cast<unsigned char>(c)))
274
0
      || ((mask & char_class_print) && (std::isprint)(static_cast<unsigned char>(c)))
275
0
      || ((mask & char_class_cntrl) && (std::iscntrl)(static_cast<unsigned char>(c)))
276
0
      || ((mask & char_class_upper) && (std::isupper)(static_cast<unsigned char>(c)))
277
0
      || ((mask & char_class_lower) && (std::islower)(static_cast<unsigned char>(c)))
278
0
      || ((mask & char_class_alpha) && (std::isalpha)(static_cast<unsigned char>(c)))
279
0
      || ((mask & char_class_digit) && (std::isdigit)(static_cast<unsigned char>(c)))
280
0
      || ((mask & char_class_punct) && (std::ispunct)(static_cast<unsigned char>(c)))
281
0
      || ((mask & char_class_xdigit) && (std::isxdigit)(static_cast<unsigned char>(c)))
282
0
      || ((mask & char_class_blank) && (std::isspace)(static_cast<unsigned char>(c)) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c))
283
0
      || ((mask & char_class_word) && (c == '_'))
284
0
      || ((mask & char_class_vertical) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == '\v')))
285
0
      || ((mask & char_class_horizontal) && (std::isspace)(static_cast<unsigned char>(c)) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && (c != '\v'));
286
0
}
287
288
inline c_regex_traits<char>::string_type  c_regex_traits<char>::lookup_collatename(const char* p1, const char* p2)
289
0
{
290
0
   std::string s(p1, p2);
291
0
   s = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(s);
292
0
   if (s.empty() && (p2 - p1 == 1))
293
0
      s.append(1, *p1);
294
0
   return s;
295
0
}
296
297
inline int  c_regex_traits<char>::value(char c, int radix)
298
0
{
299
0
   char b[2] = { c, '\0', };
300
0
   char* ep;
301
0
   int result = std::strtol(b, &ep, radix);
302
0
   if (ep == b)
303
0
      return -1;
304
0
   return result;
305
0
}
306
307
#ifndef BOOST_NO_WREGEX
308
309
inline c_regex_traits<wchar_t>::string_type  c_regex_traits<wchar_t>::transform(const wchar_t* p1, const wchar_t* p2)
310
0
{
311
0
   std::size_t r;
312
0
   std::size_t s = 10;
313
0
   std::wstring src(p1, p2);
314
0
   std::wstring result(s, L' ');
315
0
   while (s < (r = std::wcsxfrm(&*result.begin(), src.c_str(), s)))
316
0
   {
317
#if defined(_CPPLIB_VER)
318
      //
319
      // A bug in VC11 and 12 causes the program to hang if we pass a null-string
320
      // to std::strxfrm, but only for certain locales :-(
321
      // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware).
322
      //
323
      if (r == INT_MAX)
324
      {
325
         result.erase();
326
         result.insert(result.begin(), static_cast<wchar_t>(0));
327
         return result;
328
      }
329
#endif
330
0
      result.append(r - s + 3, L' ');
331
0
      s = result.size();
332
0
   }
333
0
   result.erase(r);
334
0
   return result;
335
0
}
336
337
inline c_regex_traits<wchar_t>::string_type  c_regex_traits<wchar_t>::transform_primary(const wchar_t* p1, const wchar_t* p2)
338
0
{
339
0
   static wchar_t s_delim;
340
0
   static const int s_collate_type = ::boost::BOOST_REGEX_DETAIL_NS::find_sort_syntax(static_cast<const c_regex_traits<wchar_t>*>(0), &s_delim);
341
0
   std::wstring result;
342
   //
343
   // What we do here depends upon the format of the sort key returned by
344
   // sort key returned by this->transform:
345
   //
346
0
   switch (s_collate_type)
347
0
   {
348
0
   case ::boost::BOOST_REGEX_DETAIL_NS::sort_C:
349
0
   case ::boost::BOOST_REGEX_DETAIL_NS::sort_unknown:
350
      // the best we can do is translate to lower case, then get a regular sort key:
351
0
   {
352
0
      result.assign(p1, p2);
353
0
      for (std::wstring::size_type i = 0; i < result.size(); ++i)
354
0
         result[i] = (std::towlower)(result[i]);
355
0
      result = c_regex_traits<wchar_t>::transform(&*result.begin(), &*result.begin() + result.size());
356
0
      break;
357
0
   }
358
0
   case ::boost::BOOST_REGEX_DETAIL_NS::sort_fixed:
359
0
   {
360
      // get a regular sort key, and then truncate it:
361
0
      result = c_regex_traits<wchar_t>::transform(&*result.begin(), &*result.begin() + result.size());
362
0
      result.erase(s_delim);
363
0
      break;
364
0
   }
365
0
   case ::boost::BOOST_REGEX_DETAIL_NS::sort_delim:
366
      // get a regular sort key, and then truncate everything after the delim:
367
0
      result = c_regex_traits<wchar_t>::transform(&*result.begin(), &*result.begin() + result.size());
368
0
      if ((!result.empty()) && (result[0] == s_delim))
369
0
         break;
370
0
      std::size_t i;
371
0
      for (i = 0; i < result.size(); ++i)
372
0
      {
373
0
         if (result[i] == s_delim)
374
0
            break;
375
0
      }
376
0
      result.erase(i);
377
0
      break;
378
0
   }
379
0
   if (result.empty())
380
0
      result = std::wstring(1, char(0));
381
0
   return result;
382
0
}
383
384
inline c_regex_traits<wchar_t>::char_class_type  c_regex_traits<wchar_t>::lookup_classname(const wchar_t* p1, const wchar_t* p2)
385
0
{
386
0
   using namespace BOOST_REGEX_DETAIL_NS;
387
0
   static const char_class_type masks[] =
388
0
   {
389
0
      0,
390
0
      char_class_alnum,
391
0
      char_class_alpha,
392
0
      char_class_blank,
393
0
      char_class_cntrl,
394
0
      char_class_digit,
395
0
      char_class_digit,
396
0
      char_class_graph,
397
0
      char_class_horizontal,
398
0
      char_class_lower,
399
0
      char_class_lower,
400
0
      char_class_print,
401
0
      char_class_punct,
402
0
      char_class_space,
403
0
      char_class_space,
404
0
      char_class_upper,
405
0
      char_class_unicode,
406
0
      char_class_upper,
407
0
      char_class_vertical,
408
0
      char_class_alnum | char_class_word,
409
0
      char_class_alnum | char_class_word,
410
0
      char_class_xdigit,
411
0
   };
412
413
0
   int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2);
414
0
   if (idx < 0)
415
0
   {
416
0
      std::wstring s(p1, p2);
417
0
      for (std::wstring::size_type i = 0; i < s.size(); ++i)
418
0
         s[i] = (std::towlower)(s[i]);
419
0
      idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size());
420
0
   }
421
0
   BOOST_REGEX_ASSERT(idx + 1 < static_cast<int>(sizeof(masks) / sizeof(masks[0])));
422
0
   return masks[idx + 1];
423
0
}
Unexecuted instantiation: boost::c_regex_traits<wchar_t>::lookup_classname(wchar_t const*, wchar_t const*)
Unexecuted instantiation: boost::c_regex_traits<wchar_t>::lookup_classname(wchar_t const*, wchar_t const*)
424
425
inline bool  c_regex_traits<wchar_t>::isctype(wchar_t c, char_class_type mask)
426
0
{
427
0
   using namespace BOOST_REGEX_DETAIL_NS;
428
0
   return
429
0
      ((mask & char_class_space) && (std::iswspace)(c))
430
0
      || ((mask & char_class_print) && (std::iswprint)(c))
431
0
      || ((mask & char_class_cntrl) && (std::iswcntrl)(c))
432
0
      || ((mask & char_class_upper) && (std::iswupper)(c))
433
0
      || ((mask & char_class_lower) && (std::iswlower)(c))
434
0
      || ((mask & char_class_alpha) && (std::iswalpha)(c))
435
0
      || ((mask & char_class_digit) && (std::iswdigit)(c))
436
0
      || ((mask & char_class_punct) && (std::iswpunct)(c))
437
0
      || ((mask & char_class_xdigit) && (std::iswxdigit)(c))
438
0
      || ((mask & char_class_blank) && (std::iswspace)(c) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c))
439
0
      || ((mask & char_class_word) && (c == '_'))
440
0
      || ((mask & char_class_unicode) && (c & ~static_cast<wchar_t>(0xff)))
441
0
      || ((mask & char_class_vertical) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == L'\v')))
442
0
      || ((mask & char_class_horizontal) && (std::iswspace)(c) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && (c != L'\v'));
443
0
}
444
445
inline c_regex_traits<wchar_t>::string_type  c_regex_traits<wchar_t>::lookup_collatename(const wchar_t* p1, const wchar_t* p2)
446
0
{
447
0
   std::string name;
448
   // Usual msvc warning suppression does not work here with std::string template constructor.... use a workaround instead:
449
0
   for (const wchar_t* pos = p1; pos != p2; ++pos)
450
0
      name.push_back((char)*pos);
451
0
   name = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(name);
452
0
   if (!name.empty())
453
0
      return string_type(name.begin(), name.end());
454
0
   if (p2 - p1 == 1)
455
0
      return string_type(1, *p1);
456
0
   return string_type();
457
0
}
458
459
inline int  c_regex_traits<wchar_t>::value(wchar_t c, int radix)
460
0
{
461
#ifdef BOOST_BORLANDC
462
   // workaround for broken wcstol:
463
   if ((std::iswxdigit)(c) == 0)
464
      return -1;
465
#endif
466
0
   wchar_t b[2] = { c, '\0', };
467
0
   wchar_t* ep;
468
0
   int result = std::wcstol(b, &ep, radix);
469
0
   if (ep == b)
470
0
      return -1;
471
0
   return result;
472
0
}
473
474
#endif
475
476
}
477
478
#endif
479
480
481