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-error.h"
00046 #include "sbuild-parse-value.h"
00047 #include "sbuild-types.h"
00048 #include "sbuild-util.h"
00049 
00050 namespace sbuild
00051 {
00052 
00059   class keyfile
00060   {
00061   private:
00063     typedef std::tr1::tuple<std::string,std::string,std::string> item_type;
00064 
00066     typedef std::map<std::string,item_type> item_map_type;
00067 
00069     typedef std::tr1::tuple<std::string,item_map_type,std::string> group_type;
00070 
00072     typedef std::map<std::string,group_type> group_map_type;
00073 
00074   public:
00076     enum priority
00077       {
00078         PRIORITY_OPTIONAL,   
00079         PRIORITY_REQUIRED,   
00080         PRIORITY_DISALLOWED, 
00081         PRIORITY_DEPRECATED, 
00082         PRIORITY_OBSOLETE    
00083       };
00084 
00086     typedef parse_error error;
00087 
00089     keyfile ();
00090 
00096     keyfile (std::string const& file);
00097 
00103     keyfile (std::istream& stream);
00104 
00106     virtual ~keyfile ();
00107 
00114     string_list
00115     get_groups () const;
00116 
00124     string_list
00125     get_keys (std::string const& group) const;
00126 
00133     bool
00134     has_group (std::string const& group) const;
00135 
00143     bool
00144     has_key (std::string const& group,
00145              std::string const& key) const;
00146 
00154     void
00155     set_group (std::string const& group,
00156                std::string const& comment);
00157 
00164     std::string
00165     get_comment (std::string const& group) const;
00166 
00174     std::string
00175     get_comment (std::string const& group,
00176                  std::string const& key) const;
00177 
00188     template <typename T>
00189     bool
00190     get_value (std::string const& group,
00191                std::string const& key,
00192                T&                 value) const
00193     {
00194       log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00195                             << ", key=" << key << std::endl;
00196       const item_type *found_item = find_item(group, key);
00197       if (found_item)
00198         {
00199           std::string const& strval(std::tr1::get<1>(*found_item));
00200           try
00201             {
00202               value = static_cast<T const&>(parse_value(strval));
00203               return true;
00204             }
00205           catch (parse_value::error const& e)
00206             {
00207               error ep(group, key, parse_error::NONE, e.what());
00208               log_warning() << ep.what() << std::endl;
00209               return false;
00210             }
00211         }
00212       log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00213       return false;
00214     }
00215 
00228     template <typename T>
00229     bool
00230     get_value (std::string const& group,
00231                std::string const& key,
00232                priority           priority,
00233                T&                 value) const
00234     {
00235       bool status = get_value(group, key, value);
00236       check_priority(group, key, priority, status);
00237       return status;
00238     }
00239 
00249     bool
00250     get_locale_string (std::string const& group,
00251                        std::string const& key,
00252                        std::string&       value) const;
00253 
00265     bool
00266     get_locale_string (std::string const& group,
00267                        std::string const& key,
00268                        priority           priority,
00269                        std::string&       value) const;
00270 
00281     bool
00282     get_locale_string (std::string const& group,
00283                        std::string const& key,
00284                        std::string const& locale,
00285                        std::string&       value) const;
00286 
00300     bool
00301     get_locale_string (std::string const& group,
00302                        std::string const& key,
00303                        std::string const& locale,
00304                        priority           priority,
00305                        std::string&       value) const;
00306 
00319     template <typename C>
00320     bool
00321     get_list_value (std::string const& group,
00322                     std::string const& key,
00323                     C&                 container) const
00324     {
00325       std::string item_value;
00326       if (get_value(group, key, item_value))
00327         {
00328           string_list items = split_string(item_value, this->separator);
00329           for (string_list::const_iterator pos = items.begin();
00330                pos != items.end();
00331                ++pos
00332                )
00333             {
00334               container.push_back(static_cast<typename C::const_reference>(parse_value(*pos)));
00335               // TODO: exception thrown on parse failure.
00336             }
00337           return true;
00338         }
00339       return false;
00340     }
00341 
00356     template <typename C>
00357     bool
00358     get_list_value (std::string const& group,
00359                     std::string const& key,
00360                     priority           priority,
00361                     C&                 container) const
00362     {
00363       bool status = get_list_value(group, key, container);
00364       check_priority(group, key, priority, status);
00365       return status;
00366     }
00367 
00376     template <typename T>
00377     void
00378     set_value (std::string const& group,
00379                std::string const& key,
00380                T const&           value)
00381     {
00382       set_value(group, key, value, std::string());
00383     }
00384 
00394     template <typename T>
00395     void
00396     set_value (std::string const& group,
00397                std::string const& key,
00398                T const&           value,
00399                std::string const& comment)
00400     {
00401       std::ostringstream os;
00402       os.imbue(std::locale("C"));
00403       os << std::boolalpha << value;
00404 
00405       set_group(group, "");
00406       group_type *found_group = find_group(group);
00407       assert (found_group != 0); // should not fail
00408 
00409       item_map_type& items = std::tr1::get<1>(*found_group);
00410 
00411       item_map_type::iterator pos = items.find(key);
00412       if (pos != items.end())
00413         items.erase(pos);
00414 
00415       items.insert
00416         (item_map_type::value_type(key,
00417                                    item_type(key, os.str(), comment)));
00418     }
00419 
00429     template <typename I>
00430     void
00431     set_list_value (std::string const& group,
00432                     std::string const& key,
00433                     I                  begin,
00434                     I                  end)
00435     {
00436       set_list_value(group, key, begin, end, std::string());
00437     }
00438 
00449     template <typename I>
00450     void
00451     set_list_value (std::string const& group,
00452                     std::string const& key,
00453                     I                  begin,
00454                     I                  end,
00455                     std::string const& comment)
00456     {
00457       std::string strval;
00458 
00459       for (I pos = begin; pos != end; ++ pos)
00460         {
00461           std::ostringstream os;
00462           os.imbue(std::locale("C"));
00463           os << std::boolalpha << *pos;
00464           if (os)
00465             {
00466               strval += os.str();
00467               if (pos + 1 != end)
00468                 strval += this->separator;
00469             }
00470         }
00471 
00472       set_value (group, key, strval, comment);
00473     }
00474 
00480     void
00481     remove_group (std::string const& group);
00482 
00489     void
00490     remove_key (std::string const& group,
00491                 std::string const& key);
00492 
00499     keyfile&
00500     operator += (keyfile const& rhs);
00501 
00509     friend keyfile
00510     operator + (keyfile const& lhs,
00511                 keyfile const& rhs);
00512 
00516     template <class charT, class traits>
00517     friend
00518     std::basic_istream<charT,traits>&
00519     operator >> (std::basic_istream<charT,traits>& stream,
00520                  keyfile&                          kf)
00521     {
00522       keyfile tmp;
00523       size_t linecount = 0;
00524       std::string line;
00525       std::string group;
00526       std::string comment;
00527       std::string key;
00528       std::string value;
00529 
00530       while (std::getline(stream, line))
00531       {
00532         linecount++;
00533 
00534         if (line.length() == 0)
00535           {
00536             // Empty line; do nothing.
00537           }
00538         else if (line[0] == '#') // Comment line
00539           {
00540             if (!comment.empty())
00541               comment += '\n';
00542             comment += line.substr(1);
00543           }
00544         else if (line[0] == '[') // Group
00545           {
00546             std::string::size_type fpos = line.find_first_of(']');
00547             std::string::size_type lpos = line.find_last_of(']');
00548             if (fpos == std::string::npos || lpos == std::string::npos ||
00549                 fpos != lpos)
00550               {
00551                 throw error(linecount, parse_error::INVALID_GROUP, line);
00552               }
00553             group = line.substr(1, fpos - 1);
00554 
00555             if (group.length() == 0)
00556               {
00557                 throw error(linecount, parse_error::INVALID_GROUP, line);
00558               }
00559 
00560             // Insert group
00561             if (tmp.has_group(group))
00562               {
00563                 error e(linecount, parse_error::DUPLICATE_GROUP, group);
00564                 log_warning() << e.what() << std::endl;
00565               }
00566             else
00567               tmp.set_group(group, comment);
00568             comment.clear();
00569           }
00570         else // Item
00571           {
00572             std::string::size_type pos = line.find_first_of('=');
00573             if (pos == std::string::npos)
00574               {
00575                 throw error(linecount, parse_error::INVALID_LINE, line);
00576               }
00577             if (pos == 0)
00578               {
00579                 throw error(linecount, parse_error::NO_KEY, line);
00580               }
00581             key = line.substr(0, pos);
00582             if (pos == line.length() - 1)
00583               value = "";
00584             else
00585               value = line.substr(pos + 1);
00586 
00587             // No group specified
00588             if (group.empty())
00589               {
00590                 throw error(linecount, parse_error::NO_GROUP, line);
00591               }
00592 
00593             // Insert item
00594             if (tmp.has_key(group, key))
00595               {
00596                 error e(linecount, group, parse_error::DUPLICATE_KEY, key);
00597                 log_warning() << e.what() << std::endl;
00598               }
00599             else
00600               tmp.set_value(group, key, value, comment);
00601             comment.clear();
00602           }
00603       }
00604 
00605       kf += tmp;
00606 
00607       return stream;
00608     }
00609 
00613     template <class charT, class traits>
00614     friend
00615     std::basic_ostream<charT,traits>&
00616     operator << (std::basic_ostream<charT,traits>& stream,
00617                  keyfile const&                    kf)
00618     {
00619       unsigned int group_count = 0;
00620 
00621       for (group_map_type::const_iterator gp = kf.groups.begin();
00622            gp != kf.groups.end();
00623            ++gp, ++group_count)
00624         {
00625           if (group_count > 0)
00626             stream << '\n';
00627 
00628           group_type const& group = gp->second;
00629           std::string const& groupname = std::tr1::get<0>(group);
00630           std::string const& comment = std::tr1::get<2>(group);
00631 
00632           if (comment.length() > 0)
00633             print_comment(comment, stream);
00634 
00635           stream << '[' << groupname << ']' << '\n';
00636 
00637           item_map_type const& items(std::tr1::get<1>(group));
00638           for (item_map_type::const_iterator it = items.begin();
00639                it != items.end();
00640                ++it)
00641             {
00642               item_type const& item = it->second;
00643               std::string const& key(std::tr1::get<0>(item));
00644               std::string const& value(std::tr1::get<1>(item));
00645               std::string const& comment(std::tr1::get<2>(item));
00646 
00647               if (comment.length() > 0)
00648                 print_comment(comment, stream);
00649 
00650               stream << key << '=' << value << '\n';
00651             }
00652         }
00653 
00654       return stream;
00655     }
00656 
00657   private:
00664     const group_type *
00665     find_group (std::string const& group) const;
00666 
00673     group_type *
00674     find_group (std::string const& group);
00675 
00683     const item_type *
00684     find_item (std::string const& group,
00685                std::string const& key) const;
00686 
00694     item_type *
00695     find_item (std::string const& group,
00696                std::string const& key);
00697 
00706     void
00707     check_priority (std::string const& group,
00708                     std::string const& key,
00709                     priority           priority,
00710                     bool               valid) const;
00711 
00719     static void
00720     print_comment (std::string const& comment,
00721                    std::ostream&      stream);
00722 
00724     group_map_type groups;
00726     char           separator;
00727   };
00728 
00729 }
00730 
00731 #endif /* SBUILD_KEYFILE_H */
00732 
00733 /*
00734  * Local Variables:
00735  * mode:C++
00736  * End:
00737  */

Generated on Sat Jun 17 14:41:22 2006 for schroot by  doxygen 1.4.6