blob: ff00bf8e095e9c6ab6d9d30c16826d9b4cd16307 [file] [log] [blame]
/*
* Copyright Andrey Semashev 2007 - 2015.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
/*!
* \file parser_utils.cpp
* \author Andrey Semashev
* \date 31.03.2008
*
* \brief This header is the Boost.Log library implementation, see the library documentation
* at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
*/
#ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
#include <cctype>
#include <iterator>
#include <algorithm>
#include <boost/log/exceptions.hpp>
#include "parser_utils.hpp"
#include <boost/log/detail/header.hpp>
#ifdef BOOST_LOG_USE_WCHAR_T
#include <cwctype>
#endif
namespace boost {
BOOST_LOG_OPEN_NAMESPACE
namespace aux {
#ifdef BOOST_LOG_USE_CHAR
#ifndef BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
const char_constants< char >::char_type char_constants< char >::char_comment;
const char_constants< char >::char_type char_constants< char >::char_comma;
const char_constants< char >::char_type char_constants< char >::char_dot;
const char_constants< char >::char_type char_constants< char >::char_quote;
const char_constants< char >::char_type char_constants< char >::char_percent;
const char_constants< char >::char_type char_constants< char >::char_exclamation;
const char_constants< char >::char_type char_constants< char >::char_and;
const char_constants< char >::char_type char_constants< char >::char_or;
const char_constants< char >::char_type char_constants< char >::char_equal;
const char_constants< char >::char_type char_constants< char >::char_greater;
const char_constants< char >::char_type char_constants< char >::char_less;
const char_constants< char >::char_type char_constants< char >::char_underline;
const char_constants< char >::char_type char_constants< char >::char_backslash;
const char_constants< char >::char_type char_constants< char >::char_section_bracket_left;
const char_constants< char >::char_type char_constants< char >::char_section_bracket_right;
const char_constants< char >::char_type char_constants< char >::char_paren_bracket_left;
const char_constants< char >::char_type char_constants< char >::char_paren_bracket_right;
#endif // BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
//! Skips spaces in the beginning of the input
const char* char_constants< char >::trim_spaces_left(const char_type* begin, const char_type* end)
{
using namespace std;
while (begin != end && isspace(*begin))
++begin;
return begin;
}
//! Skips spaces in the end of the input
const char* char_constants< char >::trim_spaces_right(const char_type* begin, const char_type* end)
{
using namespace std;
while (begin != end && isspace(*(end - 1)))
--end;
return end;
}
//! Scans for the attribute name placeholder in the input
const char* char_constants< char >::scan_attr_placeholder(const char_type* begin, const char_type* end)
{
using namespace std;
while (begin != end)
{
char_type c = *begin;
if (!isalnum(c) && c != char_underline)
break;
++begin;
}
return begin;
}
//! Parses an operand string (possibly quoted) from the input
const char* char_constants< char >::parse_operand(const char_type* begin, const char_type* end, string_type& operand)
{
using namespace std; // to make sure we can use C functions unqualified
const char_type* p = begin;
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Operand value is empty");
char_type c = *p;
if (c == char_quote)
{
// The value is specified as a quoted string
const char_type* start = ++p;
for (; p != end; ++p)
{
c = *p;
if (c == char_quote)
{
break;
}
else if (c == char_backslash)
{
++p;
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the argument value");
}
}
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Unterminated quoted string in the argument value");
operand.assign(start, p);
translate_escape_sequences(operand);
++p; // skip the closing quote
}
else
{
// The value is specified as a single word
const char_type* start = p;
for (++p; p != end; ++p)
{
c = *p;
if (!isalnum(c) && c != '_' && c != '-' && c != '+' && c != '.')
break;
}
operand.assign(start, p);
}
return p;
}
//! Converts escape sequences to the corresponding characters
void char_constants< char >::translate_escape_sequences(string_type& str)
{
using namespace std; // to make sure we can use C functions unqualified
string_type::iterator it = str.begin();
while (it != str.end())
{
it = std::find(it, str.end(), '\\');
if (std::distance(it, str.end()) >= 2)
{
it = str.erase(it);
switch (*it)
{
case 'n':
*it = '\n'; break;
case 'r':
*it = '\r'; break;
case 'a':
*it = '\a'; break;
case '\\':
++it; break;
case 't':
*it = '\t'; break;
case 'b':
*it = '\b'; break;
case 'x':
{
string_type::iterator b = it;
if (std::distance(++b, str.end()) >= 2)
{
char_type c1 = *b++, c2 = *b++;
if (isxdigit(c1) && isxdigit(c2))
{
*it++ = char_type((to_number(c1) << 4) | to_number(c2));
it = str.erase(it, b);
}
}
break;
}
default:
{
if (*it >= '0' && *it <= '7')
{
string_type::iterator b = it;
int c = (*b++) - '0';
if (*b >= '0' && *b <= '7')
c = c * 8 + (*b++) - '0';
if (*b >= '0' && *b <= '7')
c = c * 8 + (*b++) - '0';
*it++ = char_type(c);
it = str.erase(it, b);
}
break;
}
}
}
}
}
#endif // BOOST_LOG_USE_CHAR
#ifdef BOOST_LOG_USE_WCHAR_T
#ifndef BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_comment;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_comma;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_dot;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_quote;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_percent;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_exclamation;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_and;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_or;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_equal;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_greater;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_less;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_underline;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_backslash;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_section_bracket_left;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_section_bracket_right;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_paren_bracket_left;
const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_paren_bracket_right;
#endif // BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
//! Skips spaces in the beginning of the input
const wchar_t* char_constants< wchar_t >::trim_spaces_left(const char_type* begin, const char_type* end)
{
using namespace std;
while (begin != end && iswspace(*begin))
++begin;
return begin;
}
//! Skips spaces in the end of the input
const wchar_t* char_constants< wchar_t >::trim_spaces_right(const char_type* begin, const char_type* end)
{
using namespace std;
while (begin != end && iswspace(*(end - 1)))
--end;
return end;
}
//! Scans for the attribute name placeholder in the input
const wchar_t* char_constants< wchar_t >::scan_attr_placeholder(const char_type* begin, const char_type* end)
{
using namespace std;
while (begin != end)
{
char_type c = *begin;
if (!iswalnum(c) && c != char_underline)
break;
++begin;
}
return begin;
}
//! Parses an operand string (possibly quoted) from the input
const wchar_t* char_constants< wchar_t >::parse_operand(const char_type* begin, const char_type* end, string_type& operand)
{
using namespace std; // to make sure we can use C functions unqualified
const char_type* p = begin;
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Operand value is empty");
char_type c = *p;
if (c == char_quote)
{
// The value is specified as a quoted string
const char_type* start = ++p;
for (; p != end; ++p)
{
c = *p;
if (c == char_quote)
{
break;
}
else if (c == char_backslash)
{
++p;
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the argument value");
}
}
if (p == end)
BOOST_LOG_THROW_DESCR(parse_error, "Unterminated quoted string in the argument value");
operand.assign(start, p);
translate_escape_sequences(operand);
++p; // skip the closing quote
}
else
{
// The value is specified as a single word
const char_type* start = p;
for (++p; p != end; ++p)
{
c = *p;
if (!iswalnum(c) && c != L'_' && c != L'-' && c != L'+' && c != L'.')
break;
}
operand.assign(start, p);
}
return p;
}
//! Converts escape sequences to the corresponding characters
void char_constants< wchar_t >::translate_escape_sequences(string_type& str)
{
using namespace std; // to make sure we can use C functions unqualified
string_type::iterator it = str.begin();
while (it != str.end())
{
it = std::find(it, str.end(), L'\\');
if (std::distance(it, str.end()) >= 2)
{
it = str.erase(it);
switch (*it)
{
case L'n':
*it = L'\n'; break;
case L'r':
*it = L'\r'; break;
case L'a':
*it = L'\a'; break;
case L'\\':
++it; break;
case L't':
*it = L'\t'; break;
case L'b':
*it = L'\b'; break;
case L'x':
{
string_type::iterator b = it;
if (std::distance(++b, str.end()) >= 2)
{
char_type c1 = *b++, c2 = *b++;
if (iswxdigit(c1) && iswxdigit(c2))
{
*it++ = char_type((to_number(c1) << 4) | to_number(c2));
it = str.erase(it, b);
}
}
break;
}
case L'u':
{
string_type::iterator b = it;
if (std::distance(++b, str.end()) >= 4)
{
char_type c1 = *b++, c2 = *b++, c3 = *b++, c4 = *b++;
if (iswxdigit(c1) && iswxdigit(c2) && iswxdigit(c3) && iswxdigit(c4))
{
*it++ = char_type(
(to_number(c1) << 12) |
(to_number(c2) << 8) |
(to_number(c3) << 4) |
to_number(c4));
it = str.erase(it, b);
}
}
break;
}
case L'U':
{
string_type::iterator b = it;
if (std::distance(++b, str.end()) >= 8)
{
char_type c1 = *b++, c2 = *b++, c3 = *b++, c4 = *b++;
char_type c5 = *b++, c6 = *b++, c7 = *b++, c8 = *b++;
if (iswxdigit(c1) && iswxdigit(c2) && iswxdigit(c3) && iswxdigit(c4) &&
iswxdigit(c5) && iswxdigit(c6) && iswxdigit(c7) && iswxdigit(c8))
{
*it++ = char_type(
(to_number(c1) << 28) |
(to_number(c2) << 24) |
(to_number(c3) << 20) |
(to_number(c4) << 16) |
(to_number(c5) << 12) |
(to_number(c6) << 8) |
(to_number(c7) << 4) |
to_number(c8));
it = str.erase(it, b);
}
}
break;
}
default:
{
if (*it >= L'0' && *it <= L'7')
{
string_type::iterator b = it;
int c = (*b++) - L'0';
if (*b >= L'0' && *b <= L'7')
c = c * 8 + (*b++) - L'0';
if (*b >= L'0' && *b <= L'7')
c = c * 8 + (*b++) - L'0';
*it++ = char_type(c);
it = str.erase(it, b);
}
break;
}
}
}
}
}
#endif // BOOST_LOG_USE_WCHAR_T
} // namespace aux
BOOST_LOG_CLOSE_NAMESPACE // namespace log
} // namespace boost
#include <boost/log/detail/footer.hpp>
#endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS