• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *          Copyright Andrey Semashev 2007 - 2015.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   parser_utils.cpp
9  * \author Andrey Semashev
10  * \date   31.03.2008
11  *
12  * \brief  This header is the Boost.Log library implementation, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14  */
15 
16 #ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
17 
18 #include <boost/log/detail/setup_config.hpp>
19 #include <cctype>
20 #include <iterator>
21 #include <algorithm>
22 #include <boost/log/exceptions.hpp>
23 #include "parser_utils.hpp"
24 #include <boost/log/detail/header.hpp>
25 #ifdef BOOST_LOG_USE_WCHAR_T
26 #include <cwctype>
27 #endif
28 
29 namespace boost {
30 
31 BOOST_LOG_OPEN_NAMESPACE
32 
33 namespace aux {
34 
35 #ifdef BOOST_LOG_USE_CHAR
36 
37 #ifndef BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
38 
39 const char_constants< char >::char_type char_constants< char >::char_comment;
40 const char_constants< char >::char_type char_constants< char >::char_comma;
41 const char_constants< char >::char_type char_constants< char >::char_dot;
42 const char_constants< char >::char_type char_constants< char >::char_quote;
43 const char_constants< char >::char_type char_constants< char >::char_percent;
44 const char_constants< char >::char_type char_constants< char >::char_exclamation;
45 const char_constants< char >::char_type char_constants< char >::char_and;
46 const char_constants< char >::char_type char_constants< char >::char_or;
47 const char_constants< char >::char_type char_constants< char >::char_equal;
48 const char_constants< char >::char_type char_constants< char >::char_greater;
49 const char_constants< char >::char_type char_constants< char >::char_less;
50 const char_constants< char >::char_type char_constants< char >::char_underline;
51 const char_constants< char >::char_type char_constants< char >::char_backslash;
52 const char_constants< char >::char_type char_constants< char >::char_section_bracket_left;
53 const char_constants< char >::char_type char_constants< char >::char_section_bracket_right;
54 const char_constants< char >::char_type char_constants< char >::char_paren_bracket_left;
55 const char_constants< char >::char_type char_constants< char >::char_paren_bracket_right;
56 
57 #endif // BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
58 
59 //! Skips spaces in the beginning of the input
trim_spaces_left(const char_type * begin,const char_type * end)60 const char* char_constants< char >::trim_spaces_left(const char_type* begin, const char_type* end)
61 {
62     using namespace std;
63     while (begin != end && isspace(*begin))
64         ++begin;
65     return begin;
66 }
67 
68 //! Skips spaces in the end of the input
trim_spaces_right(const char_type * begin,const char_type * end)69 const char* char_constants< char >::trim_spaces_right(const char_type* begin, const char_type* end)
70 {
71     using namespace std;
72     while (begin != end && isspace(*(end - 1)))
73         --end;
74     return end;
75 }
76 
77 //! Scans for the attribute name placeholder in the input
scan_attr_placeholder(const char_type * begin,const char_type * end)78 const char* char_constants< char >::scan_attr_placeholder(const char_type* begin, const char_type* end)
79 {
80     using namespace std;
81     while (begin != end)
82     {
83         char_type c = *begin;
84         if (!isalnum(c) && c != char_underline)
85             break;
86         ++begin;
87     }
88 
89     return begin;
90 }
91 
92 //! Parses an operand string (possibly quoted) from the input
parse_operand(const char_type * begin,const char_type * end,string_type & operand)93 const char* char_constants< char >::parse_operand(const char_type* begin, const char_type* end, string_type& operand)
94 {
95     using namespace std; // to make sure we can use C functions unqualified
96 
97     const char_type* p = begin;
98     if (p == end)
99         BOOST_LOG_THROW_DESCR(parse_error, "Operand value is empty");
100 
101     char_type c = *p;
102     if (c == char_quote)
103     {
104         // The value is specified as a quoted string
105         const char_type* start = ++p;
106         for (; p != end; ++p)
107         {
108             c = *p;
109             if (c == char_quote)
110             {
111                 break;
112             }
113             else if (c == char_backslash)
114             {
115                 ++p;
116                 if (p == end)
117                     BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the argument value");
118             }
119         }
120         if (p == end)
121             BOOST_LOG_THROW_DESCR(parse_error, "Unterminated quoted string in the argument value");
122 
123         operand.assign(start, p);
124         translate_escape_sequences(operand);
125 
126         ++p; // skip the closing quote
127     }
128     else
129     {
130         // The value is specified as a single word
131         const char_type* start = p;
132         for (++p; p != end; ++p)
133         {
134             c = *p;
135             if (!isalnum(c) && c != '_' && c != '-' && c != '+' && c != '.')
136                 break;
137         }
138 
139         operand.assign(start, p);
140     }
141 
142     return p;
143 }
144 
145 //! Converts escape sequences to the corresponding characters
translate_escape_sequences(string_type & str)146 void char_constants< char >::translate_escape_sequences(string_type& str)
147 {
148     using namespace std; // to make sure we can use C functions unqualified
149 
150     string_type::iterator it = str.begin();
151     while (it != str.end())
152     {
153         it = std::find(it, str.end(), '\\');
154         if (std::distance(it, str.end()) >= 2)
155         {
156             it = str.erase(it);
157             switch (*it)
158             {
159             case 'n':
160                 *it = '\n'; break;
161             case 'r':
162                 *it = '\r'; break;
163             case 'a':
164                 *it = '\a'; break;
165             case '\\':
166                 ++it; break;
167             case 't':
168                 *it = '\t'; break;
169             case 'b':
170                 *it = '\b'; break;
171             case 'x':
172                 {
173                     string_type::iterator b = it;
174                     if (std::distance(++b, str.end()) >= 2)
175                     {
176                         char_type c1 = *b++, c2 = *b++;
177                         if (isxdigit(c1) && isxdigit(c2))
178                         {
179                             *it++ = char_type((to_number(c1) << 4) | to_number(c2));
180                             it = str.erase(it, b);
181                         }
182                     }
183                     break;
184                 }
185             default:
186                 {
187                     if (*it >= '0' && *it <= '7')
188                     {
189                         string_type::iterator b = it;
190                         int c = (*b++) - '0';
191                         if (*b >= '0' && *b <= '7')
192                             c = c * 8 + (*b++) - '0';
193                         if (*b >= '0' && *b <= '7')
194                             c = c * 8 + (*b++) - '0';
195 
196                         *it++ = char_type(c);
197                         it = str.erase(it, b);
198                     }
199                     break;
200                 }
201             }
202         }
203     }
204 }
205 
206 #endif // BOOST_LOG_USE_CHAR
207 
208 #ifdef BOOST_LOG_USE_WCHAR_T
209 
210 #ifndef BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
211 
212 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_comment;
213 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_comma;
214 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_dot;
215 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_quote;
216 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_percent;
217 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_exclamation;
218 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_and;
219 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_or;
220 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_equal;
221 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_greater;
222 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_less;
223 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_underline;
224 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_backslash;
225 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_section_bracket_left;
226 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_section_bracket_right;
227 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_paren_bracket_left;
228 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_paren_bracket_right;
229 
230 #endif // BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
231 
232 //! Skips spaces in the beginning of the input
trim_spaces_left(const char_type * begin,const char_type * end)233 const wchar_t* char_constants< wchar_t >::trim_spaces_left(const char_type* begin, const char_type* end)
234 {
235     using namespace std;
236     while (begin != end && iswspace(*begin))
237         ++begin;
238     return begin;
239 }
240 
241 //! Skips spaces in the end of the input
trim_spaces_right(const char_type * begin,const char_type * end)242 const wchar_t* char_constants< wchar_t >::trim_spaces_right(const char_type* begin, const char_type* end)
243 {
244     using namespace std;
245     while (begin != end && iswspace(*(end - 1)))
246         --end;
247     return end;
248 }
249 
250 //! Scans for the attribute name placeholder in the input
scan_attr_placeholder(const char_type * begin,const char_type * end)251 const wchar_t* char_constants< wchar_t >::scan_attr_placeholder(const char_type* begin, const char_type* end)
252 {
253     using namespace std;
254     while (begin != end)
255     {
256         char_type c = *begin;
257         if (!iswalnum(c) && c != char_underline)
258             break;
259         ++begin;
260     }
261 
262     return begin;
263 }
264 
265 //! Parses an operand string (possibly quoted) from the input
parse_operand(const char_type * begin,const char_type * end,string_type & operand)266 const wchar_t* char_constants< wchar_t >::parse_operand(const char_type* begin, const char_type* end, string_type& operand)
267 {
268     using namespace std; // to make sure we can use C functions unqualified
269 
270     const char_type* p = begin;
271     if (p == end)
272         BOOST_LOG_THROW_DESCR(parse_error, "Operand value is empty");
273 
274     char_type c = *p;
275     if (c == char_quote)
276     {
277         // The value is specified as a quoted string
278         const char_type* start = ++p;
279         for (; p != end; ++p)
280         {
281             c = *p;
282             if (c == char_quote)
283             {
284                 break;
285             }
286             else if (c == char_backslash)
287             {
288                 ++p;
289                 if (p == end)
290                     BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the argument value");
291             }
292         }
293         if (p == end)
294             BOOST_LOG_THROW_DESCR(parse_error, "Unterminated quoted string in the argument value");
295 
296         operand.assign(start, p);
297         translate_escape_sequences(operand);
298 
299         ++p; // skip the closing quote
300     }
301     else
302     {
303         // The value is specified as a single word
304         const char_type* start = p;
305         for (++p; p != end; ++p)
306         {
307             c = *p;
308             if (!iswalnum(c) && c != L'_' && c != L'-' && c != L'+' && c != L'.')
309                 break;
310         }
311 
312         operand.assign(start, p);
313     }
314 
315     return p;
316 }
317 
318 //! Converts escape sequences to the corresponding characters
translate_escape_sequences(string_type & str)319 void char_constants< wchar_t >::translate_escape_sequences(string_type& str)
320 {
321     using namespace std; // to make sure we can use C functions unqualified
322 
323     string_type::iterator it = str.begin();
324     while (it != str.end())
325     {
326         it = std::find(it, str.end(), L'\\');
327         if (std::distance(it, str.end()) >= 2)
328         {
329             it = str.erase(it);
330             switch (*it)
331             {
332             case L'n':
333                 *it = L'\n'; break;
334             case L'r':
335                 *it = L'\r'; break;
336             case L'a':
337                 *it = L'\a'; break;
338             case L'\\':
339                 ++it; break;
340             case L't':
341                 *it = L'\t'; break;
342             case L'b':
343                 *it = L'\b'; break;
344             case L'x':
345                 {
346                     string_type::iterator b = it;
347                     if (std::distance(++b, str.end()) >= 2)
348                     {
349                         char_type c1 = *b++, c2 = *b++;
350                         if (iswxdigit(c1) && iswxdigit(c2))
351                         {
352                             *it++ = char_type((to_number(c1) << 4) | to_number(c2));
353                             it = str.erase(it, b);
354                         }
355                     }
356                     break;
357                 }
358             case L'u':
359                 {
360                     string_type::iterator b = it;
361                     if (std::distance(++b, str.end()) >= 4)
362                     {
363                         char_type c1 = *b++, c2 = *b++, c3 = *b++, c4 = *b++;
364                         if (iswxdigit(c1) && iswxdigit(c2) && iswxdigit(c3) && iswxdigit(c4))
365                         {
366                             *it++ = char_type(
367                                 (to_number(c1) << 12) |
368                                 (to_number(c2) << 8) |
369                                 (to_number(c3) << 4) |
370                                 to_number(c4));
371                             it = str.erase(it, b);
372                         }
373                     }
374                     break;
375                 }
376             case L'U':
377                 {
378                     string_type::iterator b = it;
379                     if (std::distance(++b, str.end()) >= 8)
380                     {
381                         char_type c1 = *b++, c2 = *b++, c3 = *b++, c4 = *b++;
382                         char_type c5 = *b++, c6 = *b++, c7 = *b++, c8 = *b++;
383                         if (iswxdigit(c1) && iswxdigit(c2) && iswxdigit(c3) && iswxdigit(c4) &&
384                             iswxdigit(c5) && iswxdigit(c6) && iswxdigit(c7) && iswxdigit(c8))
385                         {
386                             *it++ = char_type(
387                                 (to_number(c1) << 28) |
388                                 (to_number(c2) << 24) |
389                                 (to_number(c3) << 20) |
390                                 (to_number(c4) << 16) |
391                                 (to_number(c5) << 12) |
392                                 (to_number(c6) << 8) |
393                                 (to_number(c7) << 4) |
394                                 to_number(c8));
395                             it = str.erase(it, b);
396                         }
397                     }
398                     break;
399                 }
400             default:
401                 {
402                     if (*it >= L'0' && *it <= L'7')
403                     {
404                         string_type::iterator b = it;
405                         int c = (*b++) - L'0';
406                         if (*b >= L'0' && *b <= L'7')
407                             c = c * 8 + (*b++) - L'0';
408                         if (*b >= L'0' && *b <= L'7')
409                             c = c * 8 + (*b++) - L'0';
410 
411                         *it++ = char_type(c);
412                         it = str.erase(it, b);
413                     }
414                     break;
415                 }
416             }
417         }
418     }
419 }
420 
421 #endif // BOOST_LOG_USE_WCHAR_T
422 
423 } // namespace aux
424 
425 BOOST_LOG_CLOSE_NAMESPACE // namespace log
426 
427 } // namespace boost
428 
429 #include <boost/log/detail/footer.hpp>
430 
431 #endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS
432