Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50:16

0001 // ----------------------------------------------------------------------------
0002 // Copyright (C) 2002-2006 Marcin Kalicinski
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. 
0005 // (See accompanying file LICENSE_1_0.txt or copy at 
0006 // http://www.boost.org/LICENSE_1_0.txt)
0007 //
0008 // For more information, see www.boost.org
0009 // ----------------------------------------------------------------------------
0010 #ifndef BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_READ_HPP_INCLUDED
0011 #define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_READ_HPP_INCLUDED
0012 
0013 #include "boost/property_tree/ptree.hpp"
0014 #include "boost/property_tree/detail/info_parser_error.hpp"
0015 #include "boost/property_tree/detail/info_parser_utils.hpp"
0016 #include <iterator>
0017 #include <string>
0018 #include <stack>
0019 #include <fstream>
0020 #include <cctype>
0021 
0022 namespace boost { namespace property_tree { namespace info_parser
0023 {
0024 
0025     // Expand known escape sequences
0026     template<class It>
0027     std::basic_string<typename std::iterator_traits<It>::value_type>
0028         expand_escapes(It b, It e)
0029     {
0030         typedef typename std::iterator_traits<It>::value_type Ch;
0031         std::basic_string<Ch> result;
0032         while (b != e)
0033         {
0034             if (*b == Ch('\\'))
0035             {
0036                 ++b;
0037                 if (b == e)
0038                 {
0039                     BOOST_PROPERTY_TREE_THROW(info_parser_error(
0040                         "character expected after backslash", "", 0));
0041                 }
0042                 else if (*b == Ch('0')) result += Ch('\0');
0043                 else if (*b == Ch('a')) result += Ch('\a');
0044                 else if (*b == Ch('b')) result += Ch('\b');
0045                 else if (*b == Ch('f')) result += Ch('\f');
0046                 else if (*b == Ch('n')) result += Ch('\n');
0047                 else if (*b == Ch('r')) result += Ch('\r');
0048                 else if (*b == Ch('t')) result += Ch('\t');
0049                 else if (*b == Ch('v')) result += Ch('\v');
0050                 else if (*b == Ch('"')) result += Ch('"');
0051                 else if (*b == Ch('\'')) result += Ch('\'');
0052                 else if (*b == Ch('\\')) result += Ch('\\');
0053                 else
0054                     BOOST_PROPERTY_TREE_THROW(info_parser_error(
0055                         "unknown escape sequence", "", 0));
0056             }
0057             else
0058                 result += *b;
0059             ++b;
0060         }
0061         return result;
0062     }
0063     
0064     // Detect whitespace in a not very smart way.
0065     template <class Ch>
0066     bool is_ascii_space(Ch c)
0067     {
0068         // Everything outside ASCII is not space.
0069         unsigned n = c;
0070         if (n > 127)
0071             return false;
0072         return std::isspace(c) != 0;
0073     }
0074 
0075     // Advance pointer past whitespace
0076     template<class Ch>
0077     void skip_whitespace(const Ch *&text)
0078     {
0079         using namespace std;
0080         while (is_ascii_space(*text))
0081             ++text;
0082     }
0083 
0084     // Extract word (whitespace delimited) and advance pointer accordingly
0085     template<class Ch>
0086     std::basic_string<Ch> read_word(const Ch *&text)
0087     {
0088         using namespace std;
0089         skip_whitespace(text);
0090         const Ch *start = text;
0091         while (!is_ascii_space(*text) && *text != Ch(';') && *text != Ch('\0'))
0092             ++text;
0093         return expand_escapes(start, text);
0094     }
0095 
0096     // Extract line (eol delimited) and advance pointer accordingly
0097     template<class Ch>
0098     std::basic_string<Ch> read_line(const Ch *&text)
0099     {
0100         using namespace std;
0101         skip_whitespace(text);
0102         const Ch *start = text;
0103         while (*text != Ch('\0') && *text != Ch(';'))
0104             ++text;
0105         while (text > start && is_ascii_space(*(text - 1)))
0106             --text;
0107         return expand_escapes(start, text);
0108     }
0109 
0110     // Extract string (inside ""), and advance pointer accordingly
0111     // Set need_more_lines to true if \ continuator found
0112     template<class Ch>
0113     std::basic_string<Ch> read_string(const Ch *&text, bool *need_more_lines)
0114     {
0115         skip_whitespace(text);
0116         if (*text == Ch('\"'))
0117         {
0118 
0119             // Skip "
0120             ++text;
0121 
0122             // Find end of string, but skip escaped "
0123             bool escaped = false;
0124             const Ch *start = text;
0125             while ((escaped || *text != Ch('\"')) && *text != Ch('\0'))
0126             {
0127                 escaped = (!escaped && *text == Ch('\\'));
0128                 ++text;
0129             }
0130 
0131             // If end of string found
0132             if (*text == Ch('\"'))
0133             {
0134                 std::basic_string<Ch> result = expand_escapes(start, text++);
0135                 skip_whitespace(text);
0136                 if (*text == Ch('\\'))
0137                 {
0138                     if (!need_more_lines)
0139                         BOOST_PROPERTY_TREE_THROW(info_parser_error(
0140                             "unexpected \\", "", 0));
0141                     ++text;
0142                     skip_whitespace(text);
0143                     if (*text == Ch('\0') || *text == Ch(';'))
0144                         *need_more_lines = true;
0145                     else
0146                         BOOST_PROPERTY_TREE_THROW(info_parser_error(
0147                             "expected end of line after \\", "", 0));
0148                 }
0149                 else
0150                     if (need_more_lines)
0151                         *need_more_lines = false;
0152                 return result;
0153             }
0154             else
0155                 BOOST_PROPERTY_TREE_THROW(info_parser_error(
0156                     "unexpected end of line", "", 0));
0157 
0158         }
0159         else
0160             BOOST_PROPERTY_TREE_THROW(info_parser_error("expected \"", "", 0));
0161     }
0162 
0163     // Extract key
0164     template<class Ch>
0165     std::basic_string<Ch> read_key(const Ch *&text)
0166     {
0167         skip_whitespace(text);
0168         if (*text == Ch('\"'))
0169             return read_string(text, NULL);
0170         else
0171             return read_word(text);
0172     }
0173 
0174     // Extract data
0175     template<class Ch>
0176     std::basic_string<Ch> read_data(const Ch *&text, bool *need_more_lines)
0177     {
0178         skip_whitespace(text);
0179         if (*text == Ch('\"'))
0180             return read_string(text, need_more_lines);
0181         else
0182         {
0183             *need_more_lines = false;
0184             return read_word(text);
0185         }
0186     }
0187 
0188     // Build ptree from info stream
0189     template<class Ptree, class Ch>
0190     void read_info_internal(std::basic_istream<Ch> &stream,
0191                             Ptree &pt,
0192                             const std::string &filename,
0193                             int include_depth)
0194     {
0195         typedef std::basic_string<Ch> str_t;
0196         // Possible parser states
0197         enum state_t {
0198             s_key,              // Parser expects key
0199             s_data,             // Parser expects data
0200             s_data_cont         // Parser expects data continuation
0201         };
0202 
0203         unsigned long line_no = 0;
0204         state_t state = s_key;          // Parser state
0205         Ptree *last = NULL;             // Pointer to last created ptree
0206         // Define line here to minimize reallocations
0207         str_t line;
0208 
0209         // Initialize ptree stack (used to handle nesting)
0210         std::stack<Ptree *> stack;
0211         stack.push(&pt);                // Push root ptree on stack initially
0212 
0213         try {
0214             // While there are characters in the stream
0215             while (stream.good()) {
0216                 // Read one line from stream
0217                 ++line_no;
0218                 std::getline(stream, line);
0219                 if (!stream.good() && !stream.eof())
0220                     BOOST_PROPERTY_TREE_THROW(info_parser_error(
0221                         "read error", filename, line_no));
0222                 const Ch *text = line.c_str();
0223 
0224                 // If directive found
0225                 skip_whitespace(text);
0226                 if (*text == Ch('#')) {
0227                     // Determine directive type
0228                     ++text;     // skip #
0229                     std::basic_string<Ch> directive = read_word(text);
0230                     if (directive == convert_chtype<Ch, char>("include")) {
0231                         // #include
0232                         if (include_depth > 100) {
0233                             BOOST_PROPERTY_TREE_THROW(info_parser_error(
0234                                 "include depth too large, "
0235                                 "probably recursive include",
0236                                 filename, line_no));
0237                         }
0238                         str_t s = read_string(text, NULL);
0239                         std::string inc_name =
0240                             convert_chtype<char, Ch>(s.c_str());
0241                         std::basic_ifstream<Ch> inc_stream(inc_name.c_str());
0242                         if (!inc_stream.good())
0243                             BOOST_PROPERTY_TREE_THROW(info_parser_error(
0244                                 "cannot open include file " + inc_name,
0245                                 filename, line_no));
0246                         read_info_internal(inc_stream, *stack.top(),
0247                                            inc_name, include_depth + 1);
0248                     } else {   // Unknown directive
0249                         BOOST_PROPERTY_TREE_THROW(info_parser_error(
0250                             "unknown directive", filename, line_no));
0251                     }
0252 
0253                     // Directive must be followed by end of line
0254                     skip_whitespace(text);
0255                     if (*text != Ch('\0')) {
0256                         BOOST_PROPERTY_TREE_THROW(info_parser_error(
0257                             "expected end of line", filename, line_no));
0258                     }
0259 
0260                     // Go to next line
0261                     continue;
0262                 }
0263 
0264                 // While there are characters left in line
0265                 while (1) {
0266 
0267                     // Stop parsing on end of line or comment
0268                     skip_whitespace(text);
0269                     if (*text == Ch('\0') || *text == Ch(';')) {
0270                         if (state == s_data)    // If there was no data set state to s_key
0271                             state = s_key;
0272                         break;
0273                     }
0274 
0275                     // Process according to current parser state
0276                     switch (state)
0277                     {
0278 
0279                         // Parser expects key
0280                         case s_key:
0281                         {
0282 
0283                             if (*text == Ch('{'))   // Brace opening found
0284                             {
0285                                 if (!last)
0286                                     BOOST_PROPERTY_TREE_THROW(info_parser_error("unexpected {", "", 0));
0287                                 stack.push(last);
0288                                 last = NULL;
0289                                 ++text;
0290                             }
0291                             else if (*text == Ch('}'))  // Brace closing found
0292                             {
0293                                 if (stack.size() <= 1)
0294                                     BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched }", "", 0));
0295                                 stack.pop();
0296                                 last = NULL;
0297                                 ++text;
0298                             }
0299                             else    // Key text found
0300                             {
0301                                 std::basic_string<Ch> key = read_key(text);
0302                                 last = &stack.top()->push_back(
0303                                     std::make_pair(key, Ptree()))->second;
0304                                 state = s_data;
0305                             }
0306 
0307                         }; break;
0308 
0309                         // Parser expects data
0310                         case s_data:
0311                         {
0312                             
0313                             // Last ptree must be defined because we are going to add data to it
0314                             BOOST_ASSERT(last);
0315                             
0316                             if (*text == Ch('{'))   // Brace opening found
0317                             {
0318                                 stack.push(last);
0319                                 last = NULL;
0320                                 ++text;
0321                                 state = s_key;
0322                             }
0323                             else if (*text == Ch('}'))  // Brace closing found
0324                             {
0325                                 if (stack.size() <= 1)
0326                                     BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched }", "", 0));
0327                                 stack.pop();
0328                                 last = NULL;
0329                                 ++text;
0330                                 state = s_key;
0331                             }
0332                             else    // Data text found
0333                             {
0334                                 bool need_more_lines;
0335                                 std::basic_string<Ch> data = read_data(text, &need_more_lines);
0336                                 last->data() = data;
0337                                 state = need_more_lines ? s_data_cont : s_key;
0338                             }
0339 
0340 
0341                         }; break;
0342 
0343                         // Parser expects continuation of data after \ on previous line
0344                         case s_data_cont:
0345                         {
0346                             
0347                             // Last ptree must be defined because we are going to update its data
0348                             BOOST_ASSERT(last);
0349                             
0350                             if (*text == Ch('\"'))  // Continuation must start with "
0351                             {
0352                                 bool need_more_lines;
0353                                 std::basic_string<Ch> data = read_string(text, &need_more_lines);
0354                                 last->put_value(last->template get_value<std::basic_string<Ch> >() + data);
0355                                 state = need_more_lines ? s_data_cont : s_key;
0356                             }
0357                             else
0358                                 BOOST_PROPERTY_TREE_THROW(info_parser_error("expected \" after \\ in previous line", "", 0));
0359 
0360                         }; break;
0361 
0362                         // Should never happen
0363                         default:
0364                             BOOST_ASSERT(0);
0365 
0366                     }
0367                 }
0368             }
0369 
0370             // Check if stack has initial size, otherwise some {'s have not been closed
0371             if (stack.size() != 1)
0372                 BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched {", "", 0));
0373 
0374         }
0375         catch (info_parser_error &e)
0376         {
0377             // If line undefined rethrow error with correct filename and line
0378             if (e.line() == 0)
0379             {
0380                 BOOST_PROPERTY_TREE_THROW(info_parser_error(e.message(), filename, line_no));
0381             }
0382             else
0383                 BOOST_PROPERTY_TREE_THROW(e);
0384 
0385         }
0386 
0387     }
0388 
0389 } } }
0390 
0391 #endif