Ticket #12259: ini_parser.patch

File ini_parser.patch, 10.5 KB (added by anonymous, 5 years ago)
  • ini_parser.hpp

    old new  
    2222
    2323namespace boost { namespace property_tree { namespace ini_parser
    2424{
     25    template <class Str>
     26    inline Str comment_key()
     27    {
     28        return Str("inicomment");
     29    }
    2530
    2631    /**
    2732     * Determines whether the @c flags are valid for use with the ini_parser.
     
    6065     * @throw ini_parser_error If a format violation is found.
    6166     * @param stream Stream from which to read in the property tree.
    6267     * @param[out] pt The property tree to populate.
     68     *
     69     * Comments will be stored in the propertyTree alongside the actual property
     70     * in an additional entry \c key.inicomment (wie von comment_key() returned).
    6371     */
    6472    template<class Ptree>
    6573    void read_ini(std::basic_istream<
     
    7280        const Ch hash = stream.widen('#');
    7381        const Ch lbracket = stream.widen('[');
    7482        const Ch rbracket = stream.widen(']');
     83        const Str commentKey = comment_key<Str>();
    7584
    7685        Ptree local;
    7786        unsigned long line_no = 0;
    7887        Ptree *section = 0;
    7988        Str line;
     89        Str lastComment;
    8090
    8191        // For all lines
    8292        while (stream.good())
     
    96106                // Comment, section or key?
    97107                if (line[0] == semicolon || line[0] == hash)
    98108                {
    99                     // Ignore comments
     109                    // Save comments to intermediate storage
     110                    if (lastComment.size() > 0)
     111                        lastComment += Ch('\n');
     112                    if (line.size() >= 2)
     113                    {
     114                        if (std::isspace(line[1]) )
     115                            lastComment += line.substr(2);
     116                        else
     117                            lastComment += line.substr(1);
     118                    }
    100119                }
    101120                else if (line[0] == lbracket)
    102121                {
     
    114133                            "duplicate section name", "", line_no));
    115134                    section = &local.push_back(
    116135                        std::make_pair(key, Ptree()))->second;
     136                    if (lastComment.size() > 0)
     137                    {
     138                        if (section)
     139                            section->put(commentKey, lastComment);
     140                        lastComment.clear();
     141                    }
    117142                }
    118143                else
    119144                {
     
    132157                    if (container.find(key) != container.not_found())
    133158                        BOOST_PROPERTY_TREE_THROW(ini_parser_error(
    134159                            "duplicate key name", "", line_no));
    135                     container.push_back(std::make_pair(key, Ptree(data)));
     160                    Ptree* section = &container.push_back(std::make_pair(key, Ptree(data)))->second;
     161                    if (lastComment.size() > 0)
     162                    {
     163                        if (section)
     164                            section->put(commentKey, lastComment);
     165                        lastComment.clear();
     166                    }
    136167                }
    137168            }
    138169        }
     
    193224            }
    194225        }
    195226
     227        template<class Ptree>
     228        void write_comment(std::basic_ostream<
     229                               typename Ptree::key_type::value_type
     230                           > &stream,
     231                           const typename Ptree::key_type& comment,
     232                           const typename Ptree::key_type& commentStart)
     233        {
     234            if (comment.size() <= 0)
     235                return;
     236            typename Ptree::key_type line;
     237            bool hadNonEmptyLine = false;
     238            for (size_t i = 0; i < comment.size(); i++)
     239            {
     240                if (comment[i] == '\n')
     241                {
     242                    if (line.size() > 0 || hadNonEmptyLine)
     243                    {
     244                        // dump comment line
     245                        stream << commentStart << line << '\n';
     246                    }
     247                    else
     248                    {
     249                        // preceding empty lines are output without the commentStart
     250                        // dump comment line
     251                        stream << '\n';
     252                    }
     253                    line.clear();
     254                    hadNonEmptyLine = hadNonEmptyLine || (line.size() > 0);
     255                }
     256                else if (comment[i] != '\r')
     257                {
     258                    // Ignore '\r' (for Windows!)
     259                    line += comment[i];
     260                }
     261            }
     262            if (line.size() > 0 || hadNonEmptyLine)
     263            {
     264                // dump comment line
     265                stream << commentStart << line << '\n';
     266            }
     267            else
     268            {
     269                // preceding empty lines are output without the commentStart
     270                // dump comment line
     271                stream << '\n';
     272            }
     273        }
     274
    196275        template <typename Ptree>
    197276        void write_keys(std::basic_ostream<
    198277                                      typename Ptree::key_type::value_type
    199278                                  > &stream,
    200279                                  const Ptree& pt,
    201                                   bool throw_on_children)
     280                                  bool throw_on_children,
     281                                  const typename Ptree::key_type& commentKey,
     282                                  const typename Ptree::key_type& commentStart)
    202283        {
    203284            typedef typename Ptree::key_type::value_type Ch;
    204285            for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
    205286                 it != end; ++it)
    206287            {
    207                 if (!it->second.empty()) {
    208                     if (throw_on_children) {
     288                if (it->first != commentKey)
     289                {
     290                    // We ignore the ".comment"-nodes, as these have special meaning!
     291
     292                    // check for existence of comment node
     293                    boost::optional<typename Ptree::key_type> comment = it->second.template get_optional<typename Ptree::key_type>(commentKey);
     294
     295                    if (!it->second.empty() && !(it->second.size() == 1 && comment))
     296                    {
     297                        //only two depth-levels are allowd in INI-files ... but we also have to filter out the additional .comment nodes
     298                        if (throw_on_children)
     299                        {
    209300                        BOOST_PROPERTY_TREE_THROW(ini_parser_error(
    210                             "ptree is too deep", "", 0));
     301                                "ptree is too deep (only two depth steps alowed in INI files)", "", 0));
    211302                    }
    212303                    continue;
    213304                }
     305                    if (comment)
     306                    {
     307                        // ... if it exists: output the comment
     308                        write_comment<Ptree>(stream, *comment, commentStart);
     309                    }
    214310                stream << it->first << Ch(' ') << Ch('=') << Ch(' ')
    215311                    << it->second.template get_value<
    216312                        std::basic_string<Ch> >()
    217313                    << Ch('\n');
    218314            }
    219             stream << Ch('\n');
     315            }
    220316        }
    221317
    222318        template <typename Ptree>
    223319        void write_top_level_keys(std::basic_ostream<
    224320                                      typename Ptree::key_type::value_type
    225321                                  > &stream,
    226                                   const Ptree& pt)
     322                                  const Ptree& pt,
     323                                  const typename Ptree::key_type& commentKey,
     324                                  const typename Ptree::key_type& commentStart)
    227325        {
    228             write_keys(stream, pt, false);
     326            write_keys(stream, pt, false, commentKey, commentStart);
    229327        }
    230328
    231329        template <typename Ptree>
    232330        void write_sections(std::basic_ostream<
    233331                                typename Ptree::key_type::value_type
    234332                            > &stream,
    235                             const Ptree& pt)
     333                            const Ptree& pt,
     334                            const typename Ptree::key_type& commentKey,
     335                            const typename Ptree::key_type& commentStart)
    236336        {
    237337            typedef typename Ptree::key_type::value_type Ch;
    238338            for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
     
    243343                    if (!it->second.data().empty())
    244344                        BOOST_PROPERTY_TREE_THROW(ini_parser_error(
    245345                            "mixed data and children", "", 0));
     346                    // empty lines in front of a new section to better separate it from other sections
     347                    stream  << Ch('\n');
     348                    // check for existence of comment node
     349                    boost::optional<typename Ptree::key_type> comment = pt.template get_optional<typename Ptree::key_type>(it->first + "." + commentKey);
     350                    if (comment)
     351                    {
     352                        std::string c = *comment;
     353                        // eat linebreak from start of comment to account for the two explicit \n inserted above!
     354                        while (c.size() > 0 && c[0] == '\n')
     355                            c = c.substr(1);
     356                        // ... if it exists: output the comment
     357                        if (c.size() > 0)
     358                            write_comment<Ptree>(stream, c, commentStart);
     359                    }
    246360                    stream << Ch('[') << it->first << Ch(']') << Ch('\n');
    247                     write_keys(stream, it->second, true);
     361                    write_keys(stream, it->second, true, commentKey, commentStart);
    248362                }
    249363            }
    250364        }
     
    275389        BOOST_ASSERT(validate_flags(flags));
    276390        (void)flags;
    277391
     392        const typename Ptree::key_type commentKey = comment_key<typename Ptree::key_type>();
     393        const typename Ptree::key_type commentStart = "#";
     394
    278395        if (!pt.data().empty())
    279396            BOOST_PROPERTY_TREE_THROW(ini_parser_error(
    280397                "ptree has data on root", "", 0));
    281398        detail::check_dupes(pt);
    282399
    283         detail::write_top_level_keys(stream, pt);
    284         detail::write_sections(stream, pt);
     400        detail::write_top_level_keys(stream, pt, commentKey, commentStart);
     401        detail::write_sections(stream, pt, commentKey, commentStart);
    285402    }
    286403
    287404    /**