boost info_parse_read.hpp isspace BUG修正

来源:互联网 发布:淘宝香港高登iphone 编辑:程序博客网 时间:2024/06/04 19:36
// ----------------------------------------------------------------------------// 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 <locale>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, const std::locale& _Loc)    {        using namespace std;        while (isspace(*text, _Loc))            ++text;    }    // Extract word (whitespace delimited) and advance pointer accordingly    template<class Ch>    std::basic_string<Ch> read_word(const Ch *&text, const std::locale& _Loc)    {        using namespace std;        skip_whitespace(text, _Loc);        const Ch *start = text;        while (!isspace(*text, _Loc) && *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, const std::locale& _Loc)    {        using namespace std;        skip_whitespace(text, _Loc);        const Ch *start = text;        while (*text != Ch('\0') && *text != Ch(';'))            ++text;        while (text > start && isspace(*(text - 1), _Loc))            --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, const std::locale& _Loc)    {        skip_whitespace(text, _Loc);        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, _Loc);                if (*text == Ch('\\'))                {                    if (!need_more_lines)                        BOOST_PROPERTY_TREE_THROW(info_parser_error(                            "unexpected \\", "", 0));                    ++text;                    skip_whitespace(text, _Loc);                    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, const std::locale& _Loc)    {        skip_whitespace(text, _Loc);        if (*text == Ch('\"'))            return read_string(text, NULL, _Loc);        else            return read_word(text, _Loc);    }    // Extract data    template<class Ch>    std::basic_string<Ch> read_data(const Ch *&text, bool *need_more_lines, const std::locale& _Loc)    {        skip_whitespace(text, _Loc);        if (*text == Ch('\"'))            return read_string(text, need_more_lines, _Loc);        else        {            *need_more_lines = false;            return read_word(text, _Loc);        }    }    // 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,                             const std::locale& _Loc = std::locale(""))    {        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, _Loc);                if (*text == Ch('#')) {                    // Determine directive type                    ++text;     // skip #                    std::basic_string<Ch> directive = read_word(text, _Loc);                    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, _Loc);                        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, _Loc);                    } 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, _Loc);                    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, _Loc);                    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, _Loc);                                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, _Loc);                                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, _Loc);                                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

0 0
原创粉丝点击