Added boost header
This commit is contained in:
380
test/external/boost/property_tree/detail/info_parser_read.hpp
vendored
Normal file
380
test/external/boost/property_tree/detail/info_parser_read.hpp
vendored
Normal file
@@ -0,0 +1,380 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright (C) 2002-2006 Marcin Kalicinski
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// For more information, see www.boost.org
|
||||
// ----------------------------------------------------------------------------
|
||||
#ifndef BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_READ_HPP_INCLUDED
|
||||
#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_READ_HPP_INCLUDED
|
||||
|
||||
#include "boost/property_tree/ptree.hpp"
|
||||
#include "boost/property_tree/detail/info_parser_error.hpp"
|
||||
#include "boost/property_tree/detail/info_parser_utils.hpp"
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <stack>
|
||||
#include <fstream>
|
||||
#include <cctype>
|
||||
|
||||
namespace boost { namespace property_tree { namespace info_parser
|
||||
{
|
||||
|
||||
// Expand known escape sequences
|
||||
template<class It>
|
||||
std::basic_string<typename std::iterator_traits<It>::value_type>
|
||||
expand_escapes(It b, It e)
|
||||
{
|
||||
typedef typename std::iterator_traits<It>::value_type Ch;
|
||||
std::basic_string<Ch> result;
|
||||
while (b != e)
|
||||
{
|
||||
if (*b == Ch('\\'))
|
||||
{
|
||||
++b;
|
||||
if (b == e)
|
||||
{
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error(
|
||||
"character expected after backslash", "", 0));
|
||||
}
|
||||
else if (*b == Ch('0')) result += Ch('\0');
|
||||
else if (*b == Ch('a')) result += Ch('\a');
|
||||
else if (*b == Ch('b')) result += Ch('\b');
|
||||
else if (*b == Ch('f')) result += Ch('\f');
|
||||
else if (*b == Ch('n')) result += Ch('\n');
|
||||
else if (*b == Ch('r')) result += Ch('\r');
|
||||
else if (*b == Ch('t')) result += Ch('\t');
|
||||
else if (*b == Ch('v')) result += Ch('\v');
|
||||
else if (*b == Ch('"')) result += Ch('"');
|
||||
else if (*b == Ch('\'')) result += Ch('\'');
|
||||
else if (*b == Ch('\\')) result += Ch('\\');
|
||||
else
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error(
|
||||
"unknown escape sequence", "", 0));
|
||||
}
|
||||
else
|
||||
result += *b;
|
||||
++b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Advance pointer past whitespace
|
||||
template<class Ch>
|
||||
void skip_whitespace(const Ch *&text)
|
||||
{
|
||||
using namespace std;
|
||||
while (isspace(*text))
|
||||
++text;
|
||||
}
|
||||
|
||||
// Extract word (whitespace delimited) and advance pointer accordingly
|
||||
template<class Ch>
|
||||
std::basic_string<Ch> read_word(const Ch *&text)
|
||||
{
|
||||
using namespace std;
|
||||
skip_whitespace(text);
|
||||
const Ch *start = text;
|
||||
while (!isspace(*text) && *text != Ch(';') && *text != Ch('\0'))
|
||||
++text;
|
||||
return expand_escapes(start, text);
|
||||
}
|
||||
|
||||
// Extract line (eol delimited) and advance pointer accordingly
|
||||
template<class Ch>
|
||||
std::basic_string<Ch> read_line(const Ch *&text)
|
||||
{
|
||||
using namespace std;
|
||||
skip_whitespace(text);
|
||||
const Ch *start = text;
|
||||
while (*text != Ch('\0') && *text != Ch(';'))
|
||||
++text;
|
||||
while (text > start && isspace(*(text - 1)))
|
||||
--text;
|
||||
return expand_escapes(start, text);
|
||||
}
|
||||
|
||||
// Extract string (inside ""), and advance pointer accordingly
|
||||
// Set need_more_lines to true if \ continuator found
|
||||
template<class Ch>
|
||||
std::basic_string<Ch> read_string(const Ch *&text, bool *need_more_lines)
|
||||
{
|
||||
skip_whitespace(text);
|
||||
if (*text == Ch('\"'))
|
||||
{
|
||||
|
||||
// Skip "
|
||||
++text;
|
||||
|
||||
// Find end of string, but skip escaped "
|
||||
bool escaped = false;
|
||||
const Ch *start = text;
|
||||
while ((escaped || *text != Ch('\"')) && *text != Ch('\0'))
|
||||
{
|
||||
escaped = (!escaped && *text == Ch('\\'));
|
||||
++text;
|
||||
}
|
||||
|
||||
// If end of string found
|
||||
if (*text == Ch('\"'))
|
||||
{
|
||||
std::basic_string<Ch> result = expand_escapes(start, text++);
|
||||
skip_whitespace(text);
|
||||
if (*text == Ch('\\'))
|
||||
{
|
||||
if (!need_more_lines)
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error(
|
||||
"unexpected \\", "", 0));
|
||||
++text;
|
||||
skip_whitespace(text);
|
||||
if (*text == Ch('\0') || *text == Ch(';'))
|
||||
*need_more_lines = true;
|
||||
else
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error(
|
||||
"expected end of line after \\", "", 0));
|
||||
}
|
||||
else
|
||||
if (need_more_lines)
|
||||
*need_more_lines = false;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error(
|
||||
"unexpected end of line", "", 0));
|
||||
|
||||
}
|
||||
else
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error("expected \"", "", 0));
|
||||
}
|
||||
|
||||
// Extract key
|
||||
template<class Ch>
|
||||
std::basic_string<Ch> read_key(const Ch *&text)
|
||||
{
|
||||
skip_whitespace(text);
|
||||
if (*text == Ch('\"'))
|
||||
return read_string(text, NULL);
|
||||
else
|
||||
return read_word(text);
|
||||
}
|
||||
|
||||
// Extract data
|
||||
template<class Ch>
|
||||
std::basic_string<Ch> read_data(const Ch *&text, bool *need_more_lines)
|
||||
{
|
||||
skip_whitespace(text);
|
||||
if (*text == Ch('\"'))
|
||||
return read_string(text, need_more_lines);
|
||||
else
|
||||
{
|
||||
*need_more_lines = false;
|
||||
return read_word(text);
|
||||
}
|
||||
}
|
||||
|
||||
// Build ptree from info stream
|
||||
template<class Ptree, class Ch>
|
||||
void read_info_internal(std::basic_istream<Ch> &stream,
|
||||
Ptree &pt,
|
||||
const std::string &filename,
|
||||
int include_depth)
|
||||
{
|
||||
typedef std::basic_string<Ch> str_t;
|
||||
// Possible parser states
|
||||
enum state_t {
|
||||
s_key, // Parser expects key
|
||||
s_data, // Parser expects data
|
||||
s_data_cont // Parser expects data continuation
|
||||
};
|
||||
|
||||
unsigned long line_no = 0;
|
||||
state_t state = s_key; // Parser state
|
||||
Ptree *last = NULL; // Pointer to last created ptree
|
||||
// Define line here to minimize reallocations
|
||||
str_t line;
|
||||
|
||||
// Initialize ptree stack (used to handle nesting)
|
||||
std::stack<Ptree *> stack;
|
||||
stack.push(&pt); // Push root ptree on stack initially
|
||||
|
||||
try {
|
||||
// While there are characters in the stream
|
||||
while (stream.good()) {
|
||||
// Read one line from stream
|
||||
++line_no;
|
||||
std::getline(stream, line);
|
||||
if (!stream.good() && !stream.eof())
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error(
|
||||
"read error", filename, line_no));
|
||||
const Ch *text = line.c_str();
|
||||
|
||||
// If directive found
|
||||
skip_whitespace(text);
|
||||
if (*text == Ch('#')) {
|
||||
// Determine directive type
|
||||
++text; // skip #
|
||||
std::basic_string<Ch> directive = read_word(text);
|
||||
if (directive == convert_chtype<Ch, char>("include")) {
|
||||
// #include
|
||||
if (include_depth > 100) {
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error(
|
||||
"include depth too large, "
|
||||
"probably recursive include",
|
||||
filename, line_no));
|
||||
}
|
||||
str_t s = read_string(text, NULL);
|
||||
std::string inc_name =
|
||||
convert_chtype<char, Ch>(s.c_str());
|
||||
std::basic_ifstream<Ch> inc_stream(inc_name.c_str());
|
||||
if (!inc_stream.good())
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error(
|
||||
"cannot open include file " + inc_name,
|
||||
filename, line_no));
|
||||
read_info_internal(inc_stream, *stack.top(),
|
||||
inc_name, include_depth + 1);
|
||||
} else { // Unknown directive
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error(
|
||||
"unknown directive", filename, line_no));
|
||||
}
|
||||
|
||||
// Directive must be followed by end of line
|
||||
skip_whitespace(text);
|
||||
if (*text != Ch('\0')) {
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error(
|
||||
"expected end of line", filename, line_no));
|
||||
}
|
||||
|
||||
// Go to next line
|
||||
continue;
|
||||
}
|
||||
|
||||
// While there are characters left in line
|
||||
while (1) {
|
||||
|
||||
// Stop parsing on end of line or comment
|
||||
skip_whitespace(text);
|
||||
if (*text == Ch('\0') || *text == Ch(';')) {
|
||||
if (state == s_data) // If there was no data set state to s_key
|
||||
state = s_key;
|
||||
break;
|
||||
}
|
||||
|
||||
// Process according to current parser state
|
||||
switch (state)
|
||||
{
|
||||
|
||||
// Parser expects key
|
||||
case s_key:
|
||||
{
|
||||
|
||||
if (*text == Ch('{')) // Brace opening found
|
||||
{
|
||||
if (!last)
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error("unexpected {", "", 0));
|
||||
stack.push(last);
|
||||
last = NULL;
|
||||
++text;
|
||||
}
|
||||
else if (*text == Ch('}')) // Brace closing found
|
||||
{
|
||||
if (stack.size() <= 1)
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched }", "", 0));
|
||||
stack.pop();
|
||||
last = NULL;
|
||||
++text;
|
||||
}
|
||||
else // Key text found
|
||||
{
|
||||
std::basic_string<Ch> key = read_key(text);
|
||||
last = &stack.top()->push_back(
|
||||
std::make_pair(key, Ptree()))->second;
|
||||
state = s_data;
|
||||
}
|
||||
|
||||
}; break;
|
||||
|
||||
// Parser expects data
|
||||
case s_data:
|
||||
{
|
||||
|
||||
// Last ptree must be defined because we are going to add data to it
|
||||
BOOST_ASSERT(last);
|
||||
|
||||
if (*text == Ch('{')) // Brace opening found
|
||||
{
|
||||
stack.push(last);
|
||||
last = NULL;
|
||||
++text;
|
||||
state = s_key;
|
||||
}
|
||||
else if (*text == Ch('}')) // Brace closing found
|
||||
{
|
||||
if (stack.size() <= 1)
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched }", "", 0));
|
||||
stack.pop();
|
||||
last = NULL;
|
||||
++text;
|
||||
state = s_key;
|
||||
}
|
||||
else // Data text found
|
||||
{
|
||||
bool need_more_lines;
|
||||
std::basic_string<Ch> data = read_data(text, &need_more_lines);
|
||||
last->data() = data;
|
||||
state = need_more_lines ? s_data_cont : s_key;
|
||||
}
|
||||
|
||||
|
||||
}; break;
|
||||
|
||||
// Parser expects continuation of data after \ on previous line
|
||||
case s_data_cont:
|
||||
{
|
||||
|
||||
// Last ptree must be defined because we are going to update its data
|
||||
BOOST_ASSERT(last);
|
||||
|
||||
if (*text == Ch('\"')) // Continuation must start with "
|
||||
{
|
||||
bool need_more_lines;
|
||||
std::basic_string<Ch> data = read_string(text, &need_more_lines);
|
||||
last->put_value(last->template get_value<std::basic_string<Ch> >() + data);
|
||||
state = need_more_lines ? s_data_cont : s_key;
|
||||
}
|
||||
else
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error("expected \" after \\ in previous line", "", 0));
|
||||
|
||||
}; break;
|
||||
|
||||
// Should never happen
|
||||
default:
|
||||
BOOST_ASSERT(0);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if stack has initial size, otherwise some {'s have not been closed
|
||||
if (stack.size() != 1)
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched {", "", 0));
|
||||
|
||||
}
|
||||
catch (info_parser_error &e)
|
||||
{
|
||||
// If line undefined rethrow error with correct filename and line
|
||||
if (e.line() == 0)
|
||||
{
|
||||
BOOST_PROPERTY_TREE_THROW(info_parser_error(e.message(), filename, line_no));
|
||||
}
|
||||
else
|
||||
BOOST_PROPERTY_TREE_THROW(e);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} } }
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user