sbuild-keyfile.h

Go to the documentation of this file.
00001 /* Copyright © 2005-2006  Roger Leigh <rleigh@debian.org>
00002  *
00003  * schroot is free software; you can redistribute it and/or modify it
00004  * under the terms of the GNU General Public License as published by
00005  * the Free Software Foundation; either version 2 of the License, or
00006  * (at your option) any later version.
00007  *
00008  * schroot is distributed in the hope that it will be useful, but
00009  * WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011  * General Public License for more details.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * along with this program; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00016  * MA  02111-1307  USA
00017  *
00018  *********************************************************************/
00019 
00020 #ifndef SBUILD_KEYFILE_H
00021 #define SBUILD_KEYFILE_H
00022 
00023 #include "sbuild-config.h"
00024 
00025 #include <cassert>
00026 #include <iostream>
00027 #include <map>
00028 #include <string>
00029 #include <sstream>
00030 
00031 #ifdef HAVE_TR1_TUPLE
00032 #include <tr1/tuple>
00033 #elif HAVE_BOOST_TUPLE_TUPLE_HPP
00034 #include <boost/tuple/tuple.hpp>
00035 namespace std { namespace tr1 { using boost::tuple; using boost::get; } }
00036 #else
00037 #error A shared_ptr implementation is not available
00038 #endif
00039 
00040 #include <boost/format.hpp>
00041 
00042 #include "sbuild-error.h"
00043 #include "sbuild-i18n.h"
00044 #include "sbuild-log.h"
00045 #include "sbuild-parse-value.h"
00046 #include "sbuild-types.h"
00047 #include "sbuild-util.h"
00048 
00049 namespace sbuild
00050 {
00051 
00058   class keyfile
00059   {
00060   private:
00062     typedef std::tr1::tuple<std::string,std::string,std::string> item_type;
00063 
00065     typedef std::map<std::string,item_type> item_map_type;
00066 
00068     typedef std::tr1::tuple<std::string,item_map_type,std::string> group_type;
00069 
00071     typedef std::map<std::string,group_type> group_map_type;
00072 
00073   public:
00075     enum priority
00076       {
00077         PRIORITY_OPTIONAL,   
00078         PRIORITY_REQUIRED,   
00079         PRIORITY_DISALLOWED, 
00080         PRIORITY_DEPRECATED, 
00081         PRIORITY_OBSOLETE    
00082       };
00083 
00085     typedef runtime_error_custom<keyfile> error;
00086 
00088     keyfile ();
00089 
00095     keyfile (std::string const& file);
00096 
00102     keyfile (std::istream& stream);
00103 
00105     virtual ~keyfile ();
00106 
00113     string_list
00114     get_groups () const;
00115 
00123     string_list
00124     get_keys (std::string const& group) const;
00125 
00132     bool
00133     has_group (std::string const& group) const;
00134 
00142     bool
00143     has_key (std::string const& group,
00144              std::string const& key) const;
00145 
00153     void
00154     set_group (std::string const& group,
00155                std::string const& comment);
00156 
00163     std::string
00164     get_comment (std::string const& group) const;
00165 
00173     std::string
00174     get_comment (std::string const& group,
00175                  std::string const& key) const;
00176 
00187     template <typename T>
00188     bool
00189     get_value (std::string const& group,
00190                std::string const& key,
00191                T&                 value) const
00192     {
00193       log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00194                             << ", key=" << key << std::endl;
00195       const item_type *found_item = find_item(group, key);
00196       if (found_item)
00197         {
00198           std::string const& strval(std::tr1::get<1>(*found_item));
00199           try
00200             {
00201               value = static_cast<T const&>(parse_value(strval));
00202               return true;
00203             }
00204           catch (parse_value::error const& e)
00205             {
00206               log_warning() << boost::format("[%1%] %2%: %3%\n")
00207                 % group % key % e.what();
00208               return false;
00209             }
00210         }
00211       log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00212       return false;
00213     }
00214 
00227     template <typename T>
00228     bool
00229     get_value (std::string const& group,
00230                std::string const& key,
00231                priority           priority,
00232                T&                 value) const
00233     {
00234       bool status = get_value(group, key, value);
00235       check_priority(group, key, priority, status);
00236       return status;
00237     }
00238 
00248     bool
00249     get_locale_string (std::string const& group,
00250                        std::string const& key,
00251                        std::string&       value) const;
00252 
00264     bool
00265     get_locale_string (std::string const& group,
00266                        std::string const& key,
00267                        priority           priority,
00268                        std::string&       value) const;
00269 
00280     bool
00281     get_locale_string (std::string const& group,
00282                        std::string const& key,
00283                        std::string const& locale,
00284                        std::string&       value) const;
00285 
00299     bool
00300     get_locale_string (std::string const& group,
00301                        std::string const& key,
00302                        std::string const& locale,
00303                        priority           priority,
00304                        std::string&       value) const;
00305 
00318     template <typename C>
00319     bool
00320     get_list_value (std::string const& group,
00321                     std::string const& key,
00322                     C&                 container) const
00323     {
00324       std::string item_value;
00325       if (get_value(group, key, item_value))
00326         {
00327           string_list items = split_string(item_value, this->separator);
00328           for (string_list::const_iterator pos = items.begin();
00329                pos != items.end();
00330                ++pos
00331                )
00332             {
00333               container.push_back(static_cast<typename C::const_reference>(parse_value(*pos)));
00334               // TODO: exception thrown on parse failure.
00335             }
00336           return true;
00337         }
00338       return false;
00339     }
00340 
00355     template <typename C>
00356     bool
00357     get_list_value (std::string const& group,
00358                     std::string const& key,
00359                     priority           priority,
00360                     C&                 container) const
00361     {
00362       bool status = get_list_value(group, key, container);
00363       check_priority(group, key, priority, status);
00364       return status;
00365     }
00366 
00375     template <typename T>
00376     void
00377     set_value (std::string const& group,
00378                std::string const& key,
00379                T const&           value)
00380     {
00381       set_value(group, key, value, std::string());
00382     }
00383 
00393     template <typename T>
00394     void
00395     set_value (std::string const& group,
00396                std::string const& key,
00397                T const&           value,
00398                std::string const& comment)
00399     {
00400       std::ostringstream os;
00401       os.imbue(std::locale("C"));
00402       os << std::boolalpha << value;
00403 
00404       set_group(group, "");
00405       group_type *found_group = find_group(group);
00406       assert (found_group != 0); // should not fail
00407 
00408       item_map_type& items = std::tr1::get<1>(*found_group);
00409 
00410       item_map_type::iterator pos = items.find(key);
00411       if (pos != items.end())
00412         items.erase(pos);
00413 
00414       items.insert
00415         (item_map_type::value_type(key,
00416                                    item_type(key, os.str(), comment)));
00417     }
00418 
00428     template <typename I>
00429     void
00430     set_list_value (std::string const& group,
00431                     std::string const& key,
00432                     I                  begin,
00433                     I                  end)
00434     {
00435       set_list_value(group, key, begin, end, std::string());
00436     }
00437 
00448     template <typename I>
00449     void
00450     set_list_value (std::string const& group,
00451                     std::string const& key,
00452                     I                  begin,
00453                     I                  end,
00454                     std::string const& comment)
00455     {
00456       std::string strval;
00457 
00458       for (I pos = begin; pos != end; ++ pos)
00459         {
00460           std::ostringstream os;
00461           os.imbue(std::locale("C"));
00462           os << std::boolalpha << *pos;
00463           if (os)
00464             {
00465               strval += os.str();
00466               if (pos + 1 != end)
00467                 strval += this->separator;
00468             }
00469         }
00470 
00471       set_value (group, key, strval, comment);
00472     }
00473 
00479     void
00480     remove_group (std::string const& group);
00481 
00488     void
00489     remove_key (std::string const& group,
00490                 std::string const& key);
00491 
00498     keyfile&
00499     operator += (keyfile const& rhs);
00500 
00508     friend keyfile
00509     operator + (keyfile const& lhs,
00510                 keyfile const& rhs);
00511 
00515     template <class charT, class traits>
00516     friend
00517     std::basic_istream<charT,traits>&
00518     operator >> (std::basic_istream<charT,traits>& stream,
00519                  keyfile&                          kf)
00520     {
00521       keyfile tmp;
00522       size_t linecount = 0;
00523       std::string line;
00524       std::string group;
00525       std::string comment;
00526       std::string key;
00527       std::string value;
00528 
00529       while (std::getline(stream, line))
00530       {
00531         linecount++;
00532 
00533         if (line[0] == '#') // Comment line
00534           {
00535             if (!comment.empty())
00536               comment += '\n';
00537             comment += line.substr(1);
00538           }
00539         else if (line[0] == '[') // Group
00540           {
00541             std::string::size_type fpos = line.find_first_of(']');
00542             std::string::size_type lpos = line.find_last_of(']');
00543             if (fpos == std::string::npos || fpos != lpos)
00544               {
00545                 boost::format fmt(_("line %1%: invalid group entry: %2%"));
00546                 fmt % linecount % line;
00547                 throw error(fmt);
00548               }
00549             group = line.substr(1, fpos - 1);
00550 
00551             // Insert group
00552             if (tmp.has_group(group))
00553               {
00554                 log_warning()
00555                   << boost::format(_("line %1%: duplicate group entry: %2%"))
00556                   % linecount % group
00557                   << std::endl;
00558               }
00559             else
00560               tmp.set_group(group, comment);
00561             comment.clear();
00562           }
00563         else if (line.length() == 0)
00564           {
00565             // Empty line; do nothing.
00566           }
00567         else // Item
00568           {
00569             std::string::size_type pos = line.find_first_of('=');
00570             if (pos == std::string::npos)
00571               {
00572                 boost::format fmt(_("line %1%: invalid line: %2%"));
00573                 fmt % linecount % line;
00574                 throw error(fmt);
00575               }
00576             if (pos == 0)
00577               {
00578                 boost::format fmt(_("line %1%: no key specified: %2%"));
00579                 fmt % linecount % line;
00580                 throw error(fmt);
00581               }
00582             key = line.substr(0, pos);
00583             if (pos == line.length() - 1)
00584               value = "";
00585             else
00586               value = line.substr(pos + 1);
00587 
00588             // Insert item
00589             if (tmp.has_key(group, key))
00590               {
00591                 log_warning()
00592                   << boost::format(_("line %1%: group %2%: duplicate key entry: %3%"))
00593                   % linecount % group % key
00594                   << std::endl;
00595               }
00596             else
00597               tmp.set_value(group, key, value, comment);
00598             comment.clear();
00599           }
00600       }
00601 
00602       kf += tmp;
00603 
00604       return stream;
00605     }
00606 
00610     template <class charT, class traits>
00611     friend
00612     std::basic_ostream<charT,traits>&
00613     operator << (std::basic_ostream<charT,traits>& stream,
00614                  keyfile const&                    kf)
00615     {
00616       unsigned int group_count = 0;
00617 
00618       for (group_map_type::const_iterator gp = kf.groups.begin();
00619            gp != kf.groups.end();
00620            ++gp, ++group_count)
00621         {
00622           if (group_count > 0)
00623             stream << '\n';
00624 
00625           group_type const& group = gp->second;
00626           std::string const& groupname = std::tr1::get<0>(group);
00627           std::string const& comment = std::tr1::get<2>(group);
00628 
00629           if (comment.length() > 0)
00630             print_comment(comment, stream);
00631 
00632           stream << '[' << groupname << ']' << '\n';
00633 
00634           item_map_type const& items(std::tr1::get<1>(group));
00635           for (item_map_type::const_iterator it = items.begin();
00636                it != items.end();
00637                ++it)
00638             {
00639               item_type const& item = it->second;
00640               std::string const& key(std::tr1::get<0>(item));
00641               std::string const& value(std::tr1::get<1>(item));
00642               std::string const& comment(std::tr1::get<2>(item));
00643 
00644               if (comment.length() > 0)
00645                 print_comment(comment, stream);
00646 
00647               stream << key << '=' << value << '\n';
00648             }
00649         }
00650 
00651       return stream;
00652     }
00653 
00654   private:
00661     const group_type *
00662     find_group (std::string const& group) const;
00663 
00670     group_type *
00671     find_group (std::string const& group);
00672 
00680     const item_type *
00681     find_item (std::string const& group,
00682                std::string const& key) const;
00683 
00691     item_type *
00692     find_item (std::string const& group,
00693                std::string const& key);
00694 
00703     void
00704     check_priority (std::string const& group,
00705                     std::string const& key,
00706                     priority           priority,
00707                     bool               valid) const;
00708 
00716     static void
00717     print_comment (std::string const& comment,
00718                    std::ostream&      stream);
00719 
00721     group_map_type groups;
00723     char           separator;
00724   };
00725 
00726 }
00727 
00728 #endif /* SBUILD_KEYFILE_H */
00729 
00730 /*
00731  * Local Variables:
00732  * mode:C++
00733  * End:
00734  */

Generated on Sun Apr 30 14:07:01 2006 for schroot by  doxygen 1.4.6