sbuild-basic-keyfile.h

Go to the documentation of this file.
00001 /* Copyright © 2005-2008  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 3 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, see
00015  * <http://www.gnu.org/licenses/>.
00016  *
00017  *********************************************************************/
00018 
00019 #ifndef SBUILD_BASIC_KEYFILE_H
00020 #define SBUILD_BASIC_KEYFILE_H
00021 
00022 #include <sbuild/sbuild-i18n.h>
00023 #include <sbuild/sbuild-log.h>
00024 #include <sbuild/sbuild-keyfile-base.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 {
00043   template <typename K>
00044   class basic_keyfile_parser
00045   {
00046   public:
00048     typedef keyfile_base::error error;
00049 
00051     basic_keyfile_parser ()
00052     {
00053     }
00054 
00056     virtual ~basic_keyfile_parser ()
00057     {
00058     }
00059 
00061     typename K::group_name_type group;
00062 
00064     bool                        group_set;
00065 
00067     typename K::key_type        key;
00068 
00070     bool                        key_set;
00071 
00073     typename K::value_type      value;
00074 
00076     bool                        value_set;
00077 
00079     typename K::comment_type    comment;
00080 
00082     bool                        comment_set;
00083 
00085     typename K::size_type       line_number;
00086 
00091     virtual void
00092     begin ()
00093     {
00094       line_number = 0;
00095     }
00096 
00107     virtual void
00108     parse_line (std::string const& line)
00109     {
00110       ++line_number;
00111     }
00112 
00117     virtual void
00118     end()
00119     {
00120     }
00121   };
00122 
00129   template <typename K, typename P = basic_keyfile_parser<K> >
00130   class basic_keyfile : public keyfile_base
00131   {
00132   public:
00134     typedef typename K::group_name_type group_name_type;
00135 
00137     typedef typename K::key_type key_type;
00138 
00140     typedef typename K::value_type value_type;
00141 
00143     typedef typename K::comment_type comment_type;
00144 
00146     typedef typename K::size_type size_type;
00147 
00148   private:
00150     typedef P parse_type;
00151 
00153     typedef std::tr1::tuple<key_type,value_type,comment_type,size_type>
00154     item_type;
00155 
00157     typedef std::map<key_type,item_type> item_map_type;
00158 
00160     typedef std::tr1::tuple<group_name_type,item_map_type,comment_type,size_type> group_type;
00161 
00163     typedef std::map<group_name_type,group_type> group_map_type;
00164 
00165   public:
00167     basic_keyfile ();
00168 
00174     basic_keyfile (std::string const& file);
00175 
00181     basic_keyfile (std::istream& stream);
00182 
00184     virtual ~basic_keyfile ();
00185 
00192     string_list
00193     get_groups () const;
00194 
00202     string_list
00203     get_keys (group_name_type const& group) const;
00204 
00213     void
00214     check_keys (group_name_type const& group,
00215                 string_list const&     keys) const;
00216 
00223     bool
00224     has_group (group_name_type const& group) const;
00225 
00233     bool
00234     has_key (group_name_type const& group,
00235              key_type const&         key) const;
00236 
00244     void
00245     set_group (group_name_type const&   group,
00246                comment_type const& comment);
00247 
00256     void
00257     set_group (group_name_type const& group,
00258                comment_type const&    comment,
00259                size_type              line);
00260 
00267     comment_type
00268     get_comment (group_name_type const& group) const;
00269 
00277     comment_type
00278     get_comment (group_name_type const& group,
00279                  key_type const& key) const;
00280 
00287     size_type
00288     get_line (group_name_type const& group) const;
00289 
00297     size_type
00298     get_line (group_name_type const& group,
00299               key_type const& key) const;
00300 
00311     template <typename T>
00312     bool
00313     get_value (group_name_type const& group,
00314                key_type const& key,
00315                T&                 value) const
00316     {
00317       log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00318                             << ", key=" << key << std::endl;
00319       const item_type *found_item = find_item(group, key);
00320       if (found_item)
00321         {
00322           value_type const& strval(std::tr1::get<1>(*found_item));
00323           try
00324             {
00325               parse_value(strval, value);
00326               return true;
00327             }
00328           catch (parse_value_error const& e)
00329             {
00330               size_type line = get_line(group, key);
00331               if (line)
00332                 {
00333                   error ep(line, group, key, PASSTHROUGH_LGK, e);
00334                   log_exception_warning(ep);
00335                 }
00336               else
00337                 {
00338                   error ep(group, key, PASSTHROUGH_GK, e);
00339                   log_exception_warning(ep);
00340                 }
00341               return false;
00342             }
00343         }
00344       log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00345       return false;
00346     }
00347 
00360     template <typename T>
00361     bool
00362     get_value (group_name_type const& group,
00363                key_type const& key,
00364                priority           priority,
00365                T&                 value) const
00366     {
00367       bool status = get_value(group, key, value);
00368       check_priority(group, key, priority, status);
00369       return status;
00370     }
00371 
00381     bool
00382     get_locale_string (group_name_type const& group,
00383                        key_type const&        key,
00384                        std::string&           value) const;
00385 
00397     bool
00398     get_locale_string (group_name_type const& group,
00399                        key_type const& key,
00400                        priority           priority,
00401                        std::string&       value) const;
00402 
00413     bool
00414     get_locale_string (group_name_type const& group,
00415                        key_type const& key,
00416                        std::string const& locale,
00417                        std::string&       value) const;
00418 
00432     bool
00433     get_locale_string (group_name_type const& group,
00434                        key_type const& key,
00435                        std::string const& locale,
00436                        priority           priority,
00437                        std::string&       value) const;
00438 
00451     template <typename C>
00452     bool
00453     get_list_value (group_name_type const& group,
00454                     key_type const& key,
00455                     C&                 container) const
00456     {
00457       std::string item_value;
00458       if (get_value(group, key, item_value))
00459         {
00460           string_list items = split_string(item_value,
00461                                            std::string(1, this->separator));
00462           for (string_list::const_iterator pos = items.begin();
00463                pos != items.end();
00464                ++pos
00465                )
00466             {
00467               typename C::value_type tmp;
00468 
00469               try
00470                 {
00471                   parse_value(*pos, tmp);
00472                 }
00473               catch (parse_value_error const& e)
00474                 {
00475                   size_type line = get_line(group, key);
00476                   if (line)
00477                     {
00478                       error ep(line, group, key, PASSTHROUGH_LGK, e);
00479                       log_exception_warning(ep);
00480                     }
00481                   else
00482                     {
00483                       error ep(group, key, PASSTHROUGH_GK, e);
00484                       log_exception_warning(ep);
00485                     }
00486                   return false;
00487                 }
00488 
00489               container.push_back(tmp);
00490             }
00491           return true;
00492         }
00493       return false;
00494     }
00495 
00510     template <typename C>
00511     bool
00512     get_list_value (group_name_type const& group,
00513                     key_type const& key,
00514                     priority           priority,
00515                     C&                 container) const
00516     {
00517       bool status = get_list_value(group, key, container);
00518       check_priority(group, key, priority, status);
00519       return status;
00520     }
00521 
00530     template <typename T>
00531     void
00532     set_value (group_name_type const& group,
00533                key_type const& key,
00534                T const&           value)
00535     {
00536       set_value(group, key, value, comment_type());
00537     }
00538 
00548     template <typename T>
00549     void
00550     set_value (group_name_type const& group,
00551                key_type const& key,
00552                T const&           value,
00553                comment_type const& comment)
00554     {
00555       set_value(group, key, value, comment, 0);
00556     }
00557 
00568     template <typename T>
00569     void
00570     set_value (group_name_type const& group,
00571                key_type const& key,
00572                T const&           value,
00573                comment_type const& comment,
00574                size_type       line)
00575     {
00576       std::ostringstream os;
00577       os.imbue(std::locale::classic());
00578       os << std::boolalpha << value;
00579 
00580       set_group(group, "");
00581       group_type *found_group = find_group(group);
00582       assert (found_group != 0); // should not fail
00583 
00584       item_map_type& items = std::tr1::get<1>(*found_group);
00585 
00586       typename item_map_type::iterator pos = items.find(key);
00587       if (pos != items.end())
00588         items.erase(pos);
00589       items.insert
00590         (typename item_map_type::value_type(key,
00591                                             item_type(key, os.str(), comment, line)));
00592     }
00593 
00603     template <typename I>
00604     void
00605     set_list_value (group_name_type const& group,
00606                     key_type const& key,
00607                     I                  begin,
00608                     I                  end)
00609     {
00610       set_list_value(group, key, begin, end, comment_type());
00611     }
00612 
00623     template <typename I>
00624     void
00625     set_list_value (group_name_type const& group,
00626                     key_type const& key,
00627                     I                  begin,
00628                     I                  end,
00629                     comment_type const& comment)
00630     {
00631       set_list_value (group, key, begin, end, comment, 0);
00632     }
00633 
00645     template <typename I>
00646     void
00647     set_list_value (group_name_type const& group,
00648                     key_type const& key,
00649                     I                  begin,
00650                     I                  end,
00651                     comment_type const& comment,
00652                     size_type       line)
00653     {
00654       std::string strval;
00655 
00656       for (I pos = begin; pos != end; ++ pos)
00657         {
00658           std::ostringstream os;
00659           os.imbue(std::locale::classic());
00660           os << std::boolalpha << *pos;
00661           if (os)
00662             {
00663               strval += os.str();
00664               if (pos + 1 != end)
00665                 strval += this->separator;
00666             }
00667         }
00668 
00669       set_value (group, key, strval, comment, line);
00670     }
00671 
00677     void
00678     remove_group (group_name_type const& group);
00679 
00686     void
00687     remove_key (group_name_type const& group,
00688                 key_type const& key);
00689 
00696     basic_keyfile&
00697     operator += (basic_keyfile const& rhs);
00698 
00706     template <typename _K, typename _P>
00707     friend basic_keyfile<_K, _P>
00708     operator + (basic_keyfile<_K, _P> const& lhs,
00709                 basic_keyfile<_K, _P> const& rhs);
00710 
00718     template <class charT, class traits>
00719     friend
00720     std::basic_istream<charT,traits>&
00721     operator >> (std::basic_istream<charT,traits>& stream,
00722                  basic_keyfile&                          kf)
00723     {
00724       basic_keyfile tmp;
00725       parse_type state;
00726       std::string line;
00727 
00728       state.begin();
00729 
00730       while (std::getline(stream, line))
00731       {
00732         state.parse_line(line);
00733 
00734         // Insert group
00735         if (state.group_set)
00736           {
00737             if (tmp.has_group(state.group))
00738               throw error(state.line_number, DUPLICATE_GROUP, state.group);
00739             else
00740               tmp.set_group(state.group, state.comment, state.line_number);
00741           }
00742 
00743         // Insert item
00744         if (state.key_set && state.value_set)
00745           {
00746             if (tmp.has_key(state.group, state.key))
00747               throw error(state.line_number, state.group, DUPLICATE_KEY, state.key);
00748             else
00749               tmp.set_value(state.group, state.key, state.value, state.comment, state.line_number);
00750           }
00751       }
00752 
00753       state.end();
00754       // TODO: do inserts here as well.
00755 
00756       kf += tmp;
00757 
00758       return stream;
00759     }
00760 
00768     template <class charT, class traits>
00769     friend
00770     std::basic_ostream<charT,traits>&
00771     operator << (std::basic_ostream<charT,traits>& stream,
00772                  basic_keyfile const&                    kf)
00773     {
00774       size_type group_count = 0;
00775 
00776       for (typename group_map_type::const_iterator gp = kf.groups.begin();
00777            gp != kf.groups.end();
00778            ++gp, ++group_count)
00779         {
00780           if (group_count > 0)
00781             stream << '\n';
00782 
00783           group_type const& group = gp->second;
00784           group_name_type const& groupname = std::tr1::get<0>(group);
00785           comment_type const& comment = std::tr1::get<2>(group);
00786 
00787           if (comment.length() > 0)
00788             print_comment(comment, stream);
00789 
00790           stream << '[' << groupname << ']' << '\n';
00791 
00792           item_map_type const& items(std::tr1::get<1>(group));
00793           for (typename item_map_type::const_iterator it = items.begin();
00794                it != items.end();
00795                ++it)
00796             {
00797               item_type const& item = it->second;
00798               key_type const& key(std::tr1::get<0>(item));
00799               value_type const& value(std::tr1::get<1>(item));
00800               comment_type const& comment(std::tr1::get<2>(item));
00801 
00802               if (comment.length() > 0)
00803                 print_comment(comment, stream);
00804 
00805               stream << key << '=' << value << '\n';
00806             }
00807         }
00808 
00809       return stream;
00810     }
00811 
00812   private:
00819     const group_type *
00820     find_group (group_name_type const& group) const;
00821 
00828     group_type *
00829     find_group (group_name_type const& group);
00830 
00838     const item_type *
00839     find_item (group_name_type const& group,
00840                key_type const& key) const;
00841 
00849     item_type *
00850     find_item (group_name_type const& group,
00851                key_type const& key);
00852 
00861     void
00862     check_priority (group_name_type const& group,
00863                     key_type const& key,
00864                     priority           priority,
00865                     bool               valid) const;
00866 
00878     static void
00879     print_comment (comment_type const& comment,
00880                    std::ostream&      stream);
00881 
00883     group_map_type groups;
00885     char           separator;
00886 
00887   public:
00900     template<class C, typename T>
00901     static void
00902     set_object_value (C const&            object,
00903                       T             (C::* method)() const,
00904                       basic_keyfile&            basic_keyfile,
00905                       group_name_type const&  group,
00906                       key_type const&  key)
00907     {
00908       try
00909         {
00910           basic_keyfile.set_value(group, key, (object.*method)());
00911         }
00912       catch (std::runtime_error const& e)
00913         {
00914           throw error(group, key, PASSTHROUGH_GK, e);
00915         }
00916     }
00917 
00930     template<class C, typename T>
00931     static void
00932     set_object_value (C const&            object,
00933                       T const&      (C::* method)() const,
00934                       basic_keyfile&            basic_keyfile,
00935                       group_name_type const&  group,
00936                       key_type const&  key)
00937     {
00938       try
00939         {
00940           basic_keyfile.set_value(group, key, (object.*method)());
00941         }
00942       catch (std::runtime_error const& e)
00943         {
00944           throw error(group, key, PASSTHROUGH_GK, e);
00945         }
00946     }
00947 
00961     template<class C, typename T>
00962     static void
00963     set_object_list_value (C const&            object,
00964                            T             (C::* method)() const,
00965                            basic_keyfile&            basic_keyfile,
00966                            group_name_type const&  group,
00967                            key_type const&  key)
00968     {
00969       try
00970         {
00971           basic_keyfile.set_list_value(group, key,
00972                                  (object.*method)().begin(),
00973                                  (object.*method)().end());
00974         }
00975       catch (std::runtime_error const& e)
00976         {
00977           throw error(group, key, PASSTHROUGH_GK, e);
00978         }
00979     }
00980 
00995     template<class C, typename T>
00996     static void
00997     set_object_list_value (C const&            object,
00998                            T const&      (C::* method)() const,
00999                            basic_keyfile&            basic_keyfile,
01000                            group_name_type const&  group,
01001                            key_type const&  key)
01002     {
01003       try
01004         {
01005           basic_keyfile.set_list_value(group, key,
01006                                  (object.*method)().begin(),
01007                                  (object.*method)().end());
01008         }
01009       catch (std::runtime_error const& e)
01010         {
01011           throw error(group, key, PASSTHROUGH_GK, e);
01012         }
01013     }
01014 
01029     template<class C, typename T>
01030     static void
01031     get_object_value (C&                  object,
01032                       void          (C::* method)(T param),
01033                       basic_keyfile const&      basic_keyfile,
01034                       group_name_type const&  group,
01035                       key_type const&  key,
01036                       basic_keyfile::priority   priority)
01037     {
01038       try
01039         {
01040           T value;
01041           if (basic_keyfile.get_value(group, key, priority, value))
01042             (object.*method)(value);
01043         }
01044       catch (std::runtime_error const& e)
01045         {
01046           size_type line = basic_keyfile.get_line(group, key);
01047           if (line)
01048             throw error(line, group, key, PASSTHROUGH_LGK, e);
01049           else
01050             throw error(group, key, PASSTHROUGH_GK, e);
01051         }
01052     }
01053 
01068     template<class C, typename T>
01069     static void
01070     get_object_value (C&                  object,
01071                       void          (C::* method)(T const& param),
01072                       basic_keyfile const&      basic_keyfile,
01073                       group_name_type const&  group,
01074                       key_type const&  key,
01075                       basic_keyfile::priority   priority)
01076     {
01077       try
01078         {
01079           T value;
01080           if (basic_keyfile.get_value(group, key, priority, value))
01081             (object.*method)(value);
01082         }
01083       catch (std::runtime_error const& e)
01084         {
01085           size_type line = basic_keyfile.get_line(group, key);
01086           if (line)
01087             throw error(line, group, key, PASSTHROUGH_LGK, e);
01088           else
01089             throw error(group, key, PASSTHROUGH_GK, e);
01090         }
01091     }
01092 
01107     template<class C, typename T>
01108     static void
01109     get_object_list_value (C&                  object,
01110                            void          (C::* method)(T param),
01111                            basic_keyfile const&      basic_keyfile,
01112                            group_name_type const&  group,
01113                            key_type const&  key,
01114                            basic_keyfile::priority   priority)
01115     {
01116       try
01117         {
01118           T value;
01119           if (basic_keyfile.get_list_value(group, key, priority, value))
01120             (object.*method)(value);
01121         }
01122       catch (std::runtime_error const& e)
01123         {
01124           size_type line = basic_keyfile.get_line(group, key);
01125           if (line)
01126             throw error(line, group, key, PASSTHROUGH_LGK, e);
01127           else
01128             throw error(group, key, PASSTHROUGH_GK, e);
01129           throw error(basic_keyfile.get_line(group, key),
01130                       group, key, e);
01131         }
01132     }
01133 
01149     template<class C, typename T>
01150     static void
01151     get_object_list_value (C&                  object,
01152                            void          (C::* method)(T const& param),
01153                            basic_keyfile const&      basic_keyfile,
01154                            group_name_type const&  group,
01155                            key_type const&  key,
01156                            basic_keyfile::priority   priority)
01157     {
01158       try
01159         {
01160           T value;
01161           if (basic_keyfile.get_list_value(group, key, priority, value))
01162             (object.*method)(value);
01163         }
01164       catch (std::runtime_error const& e)
01165         {
01166           size_type line = basic_keyfile.get_line(group, key);
01167           if (line)
01168             throw error(line, group, key, PASSTHROUGH_LGK, e);
01169           else
01170             throw error(group, key, PASSTHROUGH_GK, e);
01171           throw error(basic_keyfile.get_line(group, key),
01172                       group, key, e);
01173         }
01174     }
01175   };
01176 
01177 }
01178 
01179 #include <sbuild/sbuild-basic-keyfile.tcc>
01180 
01181 #endif /* SBUILD_BASIC_KEYFILE_H */
01182 
01183 /*
01184  * Local Variables:
01185  * mode:C++
01186  * End:
01187  */

Generated on Sun May 17 18:38:54 2009 for sbuild by  doxygen 1.5.9