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/sbuild-i18n.h>
00024 #include <sbuild/sbuild-log.h>
00025 #include <sbuild/sbuild-parse-error.h>
00026 #include <sbuild/sbuild-parse-value.h>
00027 #include <sbuild/sbuild-types.h>
00028 #include <sbuild/sbuild-tr1types.h>
00029 #include <sbuild/sbuild-util.h>
00030 
00031 #include <cassert>
00032 #include <map>
00033 #include <string>
00034 #include <sstream>
00035 
00036 #include <boost/format.hpp>
00037 
00038 namespace sbuild
00039 {
00040 
00047   class keyfile
00048   {
00049   private:
00051     typedef std::tr1::tuple<std::string,std::string,std::string,unsigned int>
00052     item_type;
00053 
00055     typedef std::map<std::string,item_type> item_map_type;
00056 
00058     typedef std::tr1::tuple<std::string,item_map_type,std::string,unsigned int> group_type;
00059 
00061     typedef std::map<std::string,group_type> group_map_type;
00062 
00063   public:
00065     enum priority
00066       {
00067         PRIORITY_OPTIONAL,   
00068         PRIORITY_REQUIRED,   
00069         PRIORITY_DISALLOWED, 
00070         PRIORITY_DEPRECATED, 
00071         PRIORITY_OBSOLETE    
00072       };
00073 
00075     typedef parse_error error;
00076 
00078     keyfile ();
00079 
00085     keyfile (std::string const& file);
00086 
00092     keyfile (std::istream& stream);
00093 
00095     virtual ~keyfile ();
00096 
00103     string_list
00104     get_groups () const;
00105 
00113     string_list
00114     get_keys (std::string const& group) const;
00115 
00122     bool
00123     has_group (std::string const& group) const;
00124 
00132     bool
00133     has_key (std::string const& group,
00134              std::string const& key) const;
00135 
00143     void
00144     set_group (std::string const& group,
00145                std::string const& comment);
00146 
00147   private:
00156     void
00157     set_group (std::string const& group,
00158                std::string const& comment,
00159                unsigned int       line);
00160 
00161   public:
00168     std::string
00169     get_comment (std::string const& group) const;
00170 
00178     std::string
00179     get_comment (std::string const& group,
00180                  std::string const& key) const;
00181 
00188     unsigned int
00189     get_line (std::string const& group) const;
00190 
00198     unsigned int
00199     get_line (std::string const& group,
00200               std::string const& key) const;
00201 
00212     template <typename T>
00213     bool
00214     get_value (std::string const& group,
00215                std::string const& key,
00216                T&                 value) const
00217     {
00218       log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00219                             << ", key=" << key << std::endl;
00220       const item_type *found_item = find_item(group, key);
00221       if (found_item)
00222         {
00223           std::string const& strval(std::tr1::get<1>(*found_item));
00224           try
00225             {
00226               parse_value(strval, value);
00227               return true;
00228             }
00229           catch (parse_error const& e)
00230             {
00231               error ep(group, key, parse_error::NONE, e.what());
00232               log_warning() << ep.what() << std::endl;
00233               return false;
00234             }
00235         }
00236       log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00237       return false;
00238     }
00239 
00252     template <typename T>
00253     bool
00254     get_value (std::string const& group,
00255                std::string const& key,
00256                priority           priority,
00257                T&                 value) const
00258     {
00259       bool status = get_value(group, key, value);
00260       check_priority(group, key, priority, status);
00261       return status;
00262     }
00263 
00273     bool
00274     get_locale_string (std::string const& group,
00275                        std::string const& key,
00276                        std::string&       value) const;
00277 
00289     bool
00290     get_locale_string (std::string const& group,
00291                        std::string const& key,
00292                        priority           priority,
00293                        std::string&       value) const;
00294 
00305     bool
00306     get_locale_string (std::string const& group,
00307                        std::string const& key,
00308                        std::string const& locale,
00309                        std::string&       value) const;
00310 
00324     bool
00325     get_locale_string (std::string const& group,
00326                        std::string const& key,
00327                        std::string const& locale,
00328                        priority           priority,
00329                        std::string&       value) const;
00330 
00343     template <typename C>
00344     bool
00345     get_list_value (std::string const& group,
00346                     std::string const& key,
00347                     C&                 container) const
00348     {
00349       std::string item_value;
00350       if (get_value(group, key, item_value))
00351         {
00352           string_list items = split_string(item_value,
00353                                            std::string(1, this->separator));
00354           for (string_list::const_iterator pos = items.begin();
00355                pos != items.end();
00356                ++pos
00357                )
00358             {
00359               typename C::value_type tmp;
00360 
00361               try
00362                 {
00363                   parse_value(*pos, tmp);
00364                 }
00365               catch (parse_error const& e)
00366                 {
00367                   error ep(group, key, parse_error::NONE, e.what());
00368                   log_warning() << ep.what() << std::endl;
00369                   return false;
00370                 }
00371 
00372               container.push_back(tmp);
00373             }
00374           return true;
00375         }
00376       return false;
00377     }
00378 
00393     template <typename C>
00394     bool
00395     get_list_value (std::string const& group,
00396                     std::string const& key,
00397                     priority           priority,
00398                     C&                 container) const
00399     {
00400       bool status = get_list_value(group, key, container);
00401       check_priority(group, key, priority, status);
00402       return status;
00403     }
00404 
00413     template <typename T>
00414     void
00415     set_value (std::string const& group,
00416                std::string const& key,
00417                T const&           value)
00418     {
00419       set_value(group, key, value, std::string());
00420     }
00421 
00431     template <typename T>
00432     void
00433     set_value (std::string const& group,
00434                std::string const& key,
00435                T const&           value,
00436                std::string const& comment)
00437     {
00438       std::ostringstream os;
00439       os.imbue(std::locale("C"));
00440       os << std::boolalpha << value;
00441 
00442       set_value(group, key, os.str(), comment, 0);
00443     }
00444 
00445   private:
00456     void
00457     set_value (std::string const& group,
00458                std::string const& key,
00459                std::string const& value,
00460                std::string const& comment,
00461                unsigned int       line)
00462     {
00463       set_group(group, "");
00464       group_type *found_group = find_group(group);
00465       assert (found_group != 0); // should not fail
00466 
00467       item_map_type& items = std::tr1::get<1>(*found_group);
00468 
00469       item_map_type::iterator pos = items.find(key);
00470       if (pos != items.end())
00471         items.erase(pos);
00472       items.insert
00473         (item_map_type::value_type(key,
00474                                    item_type(key, value, comment, line)));
00475     }
00476 
00477   public:
00487     template <typename I>
00488     void
00489     set_list_value (std::string const& group,
00490                     std::string const& key,
00491                     I                  begin,
00492                     I                  end)
00493     {
00494       set_list_value(group, key, begin, end, std::string());
00495     }
00496 
00507     template <typename I>
00508     void
00509     set_list_value (std::string const& group,
00510                     std::string const& key,
00511                     I                  begin,
00512                     I                  end,
00513                     std::string const& comment)
00514     {
00515       std::string strval;
00516 
00517       for (I pos = begin; pos != end; ++ pos)
00518         {
00519           std::ostringstream os;
00520           os.imbue(std::locale("C"));
00521           os << std::boolalpha << *pos;
00522           if (os)
00523             {
00524               strval += os.str();
00525               if (pos + 1 != end)
00526                 strval += this->separator;
00527             }
00528         }
00529 
00530       set_value (group, key, strval, comment);
00531     }
00532 
00538     void
00539     remove_group (std::string const& group);
00540 
00547     void
00548     remove_key (std::string const& group,
00549                 std::string const& key);
00550 
00557     keyfile&
00558     operator += (keyfile const& rhs);
00559 
00567     friend keyfile
00568     operator + (keyfile const& lhs,
00569                 keyfile const& rhs);
00570 
00574     template <class charT, class traits>
00575     friend
00576     std::basic_istream<charT,traits>&
00577     operator >> (std::basic_istream<charT,traits>& stream,
00578                  keyfile&                          kf)
00579     {
00580       keyfile tmp;
00581       size_t linecount = 0;
00582       std::string line;
00583       std::string group;
00584       std::string comment;
00585       std::string key;
00586       std::string value;
00587 
00588       while (std::getline(stream, line))
00589       {
00590         linecount++;
00591 
00592         if (line.length() == 0)
00593           {
00594             // Empty line; do nothing.
00595           }
00596         else if (line[0] == '#') // Comment line
00597           {
00598             if (!comment.empty())
00599               comment += '\n';
00600             comment += line.substr(1);
00601           }
00602         else if (line[0] == '[') // Group
00603           {
00604             std::string::size_type fpos = line.find_first_of(']');
00605             std::string::size_type lpos = line.find_last_of(']');
00606             if (fpos == std::string::npos || lpos == std::string::npos ||
00607                 fpos != lpos)
00608               {
00609                 throw error(linecount, parse_error::INVALID_GROUP, line);
00610               }
00611             group = line.substr(1, fpos - 1);
00612 
00613             if (group.length() == 0)
00614               {
00615                 throw error(linecount, parse_error::INVALID_GROUP, line);
00616               }
00617 
00618             // Insert group
00619             if (tmp.has_group(group))
00620               {
00621                 error e(linecount, parse_error::DUPLICATE_GROUP, group);
00622                 log_warning() << e.what() << std::endl;
00623               }
00624             else
00625               tmp.set_group(group, comment, linecount);
00626             comment.clear();
00627           }
00628         else // Item
00629           {
00630             std::string::size_type pos = line.find_first_of('=');
00631             if (pos == std::string::npos)
00632               {
00633                 throw error(linecount, parse_error::INVALID_LINE, line);
00634               }
00635             if (pos == 0)
00636               {
00637                 throw error(linecount, parse_error::NO_KEY, line);
00638               }
00639             key = line.substr(0, pos);
00640             if (pos == line.length() - 1)
00641               value = "";
00642             else
00643               value = line.substr(pos + 1);
00644 
00645             // No group specified
00646             if (group.empty())
00647               {
00648                 throw error(linecount, parse_error::NO_GROUP, line);
00649               }
00650 
00651             // Insert item
00652             if (tmp.has_key(group, key))
00653               {
00654                 error e(linecount, group, parse_error::DUPLICATE_KEY, key);
00655                 log_warning() << e.what() << std::endl;
00656               }
00657             else
00658               tmp.set_value(group, key, value, comment, linecount);
00659             comment.clear();
00660           }
00661       }
00662 
00663       kf += tmp;
00664 
00665       return stream;
00666     }
00667 
00671     template <class charT, class traits>
00672     friend
00673     std::basic_ostream<charT,traits>&
00674     operator << (std::basic_ostream<charT,traits>& stream,
00675                  keyfile const&                    kf)
00676     {
00677       unsigned int group_count = 0;
00678 
00679       for (group_map_type::const_iterator gp = kf.groups.begin();
00680            gp != kf.groups.end();
00681            ++gp, ++group_count)
00682         {
00683           if (group_count > 0)
00684             stream << '\n';
00685 
00686           group_type const& group = gp->second;
00687           std::string const& groupname = std::tr1::get<0>(group);
00688           std::string const& comment = std::tr1::get<2>(group);
00689 
00690           if (comment.length() > 0)
00691             print_comment(comment, stream);
00692 
00693           stream << '[' << groupname << ']' << '\n';
00694 
00695           item_map_type const& items(std::tr1::get<1>(group));
00696           for (item_map_type::const_iterator it = items.begin();
00697                it != items.end();
00698                ++it)
00699             {
00700               item_type const& item = it->second;
00701               std::string const& key(std::tr1::get<0>(item));
00702               std::string const& value(std::tr1::get<1>(item));
00703               std::string const& comment(std::tr1::get<2>(item));
00704 
00705               if (comment.length() > 0)
00706                 print_comment(comment, stream);
00707 
00708               stream << key << '=' << value << '\n';
00709             }
00710         }
00711 
00712       return stream;
00713     }
00714 
00715   private:
00722     const group_type *
00723     find_group (std::string const& group) const;
00724 
00731     group_type *
00732     find_group (std::string const& group);
00733 
00741     const item_type *
00742     find_item (std::string const& group,
00743                std::string const& key) const;
00744 
00752     item_type *
00753     find_item (std::string const& group,
00754                std::string const& key);
00755 
00764     void
00765     check_priority (std::string const& group,
00766                     std::string const& key,
00767                     priority           priority,
00768                     bool               valid) const;
00769 
00777     static void
00778     print_comment (std::string const& comment,
00779                    std::ostream&      stream);
00780 
00782     group_map_type groups;
00784     char           separator;
00785 
00786   public:
00799     template<class C, typename T>
00800     static void
00801     set_object_value (C const&            object,
00802                       T             (C::* method)() const,
00803                       keyfile&            keyfile,
00804                       std::string const&  group,
00805                       std::string const&  key)
00806     {
00807       try
00808         {
00809           keyfile.set_value(group, key, (object.*method)());
00810         }
00811       catch (runtime_error const& e)
00812         {
00813           throw parse_error(group, key, parse_error::NONE, e.what());
00814         }
00815     }
00816 
00829     template<class C, typename T>
00830     static void
00831     set_object_value (C const&            object,
00832                       T const&      (C::* method)() const,
00833                       keyfile&            keyfile,
00834                       std::string const&  group,
00835                       std::string const&  key)
00836     {
00837       try
00838         {
00839           keyfile.set_value(group, key, (object.*method)());
00840         }
00841       catch (runtime_error const& e)
00842         {
00843           throw parse_error(group, key, parse_error::NONE, e.what());
00844         }
00845     }
00846 
00861     template<class C, typename T>
00862     static void
00863     set_object_list_value (C const&            object,
00864                            T             (C::* method)() const,
00865                            keyfile&            keyfile,
00866                            std::string const&  group,
00867                            std::string const&  key)
00868     {
00869       try
00870         {
00871           keyfile.set_list_value(group, key,
00872                                  (object.*method)().begin(),
00873                                  (object.*method)().end());
00874         }
00875       catch (runtime_error const& e)
00876         {
00877           throw parse_error(group, key, parse_error::NONE, e.what());
00878         }
00879     }
00880 
00895     template<class C, typename T>
00896     static void
00897     set_object_list_value (C const&            object,
00898                            T const&      (C::* method)() const,
00899                            keyfile&            keyfile,
00900                            std::string const&  group,
00901                            std::string const&  key)
00902     {
00903       try
00904         {
00905           keyfile.set_list_value(group, key,
00906                                  (object.*method)().begin(),
00907                                  (object.*method)().end());
00908         }
00909       catch (runtime_error const& e)
00910         {
00911           throw parse_error(group, key, parse_error::NONE, e.what());
00912         }
00913     }
00914 
00930     template<class C, typename T>
00931     static void
00932     get_object_value (C&                  object,
00933                       void          (C::* method)(T param),
00934                       keyfile const&      keyfile,
00935                       std::string const&  group,
00936                       std::string const&  key,
00937                       keyfile::priority   priority)
00938     {
00939       T value;
00940       if (keyfile.get_value(group, key, priority, value))
00941         {
00942           try
00943             {
00944               (object.*method)(value);
00945             }
00946           catch (runtime_error const& e)
00947             {
00948               throw parse_error(keyfile.get_line(group, key),
00949                                 group, key, parse_error::NONE, e.what());
00950             }
00951         }
00952     }
00953 
00969     template<class C, typename T>
00970     static void
00971     get_object_value (C&                  object,
00972                       void          (C::* method)(T const& param),
00973                       keyfile const&      keyfile,
00974                       std::string const&  group,
00975                       std::string const&  key,
00976                       keyfile::priority   priority)
00977     {
00978       T value;
00979       if (keyfile.get_value(group, key, priority, value))
00980         {
00981           try
00982             {
00983               (object.*method)(value);
00984             }
00985           catch (runtime_error const& e)
00986             {
00987               throw parse_error(keyfile.get_line(group, key),
00988                                 group, key, parse_error::NONE, e.what());
00989             }
00990         }
00991     }
00992 
01008     template<class C, typename T>
01009     static void
01010     get_object_list_value (C&                  object,
01011                            void          (C::* method)(T param),
01012                            keyfile const&      keyfile,
01013                            std::string const&  group,
01014                            std::string const&  key,
01015                            keyfile::priority   priority)
01016     {
01017       T value;
01018       if (keyfile.get_list_value(group, key, priority, value))
01019         {
01020           try
01021             {
01022               (object.*method)(value);
01023             }
01024           catch (runtime_error const& e)
01025             {
01026               throw parse_error(keyfile.get_line(group, key),
01027                                 group, key, parse_error::NONE, e.what());
01028             }
01029         }
01030     }
01031 
01047     template<class C, typename T>
01048     static void
01049     get_object_list_value (C&                  object,
01050                            void          (C::* method)(T const& param),
01051                            keyfile const&      keyfile,
01052                            std::string const&  group,
01053                            std::string const&  key,
01054                            keyfile::priority   priority)
01055     {
01056       T value;
01057       if (keyfile.get_list_value(group, key, priority, value))
01058         {
01059           try
01060             {
01061               (object.*method)(value);
01062             }
01063           catch (runtime_error const& e)
01064             {
01065               throw parse_error(keyfile.get_line(group, key),
01066                                 group, key, parse_error::NONE, e.what());
01067             }
01068         }
01069     }
01070   };
01071 
01072 }
01073 
01074 #endif /* SBUILD_KEYFILE_H */
01075 
01076 /*
01077  * Local Variables:
01078  * mode:C++
01079  * End:
01080  */

Generated on Thu Jul 6 19:21:41 2006 for schroot by  doxygen 1.4.7