sbuild-basic-keyfile.h

Go to the documentation of this file.
00001 /* Copyright © 2005-2007  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_BASIC_KEYFILE_H
00021 #define SBUILD_BASIC_KEYFILE_H
00022 
00023 #include <sbuild/sbuild-i18n.h>
00024 #include <sbuild/sbuild-log.h>
00025 #include <sbuild/sbuild-keyfile-base.h>
00026 #include <sbuild/sbuild-parse-error.h>
00027 #include <sbuild/sbuild-parse-value.h>
00028 #include <sbuild/sbuild-types.h>
00029 #include <sbuild/sbuild-tr1types.h>
00030 #include <sbuild/sbuild-util.h>
00031 
00032 #include <cassert>
00033 #include <map>
00034 #include <string>
00035 #include <sstream>
00036 
00037 #include <boost/format.hpp>
00038 
00039 namespace sbuild
00040 {
00044   template <typename K>
00045   class basic_keyfile_parser
00046   {
00047   public:
00049     typedef keyfile_base::error error;
00050 
00052     basic_keyfile_parser ()
00053     {
00054     }
00055 
00057     virtual ~basic_keyfile_parser ()
00058     {
00059     }
00060 
00062     typename K::group_name_type group;
00063 
00065     bool                        group_set;
00066 
00068     typename K::key_type        key;
00069 
00071     bool                        key_set;
00072 
00074     typename K::value_type      value;
00075 
00077     bool                        value_set;
00078 
00080     typename K::comment_type    comment;
00081 
00083     bool                        comment_set;
00084 
00086     typename K::size_type       line_number;
00087 
00092     virtual void
00093     begin ()
00094     {
00095       line_number = 0;
00096     }
00097 
00108     virtual void
00109     parse_line (std::string const& line)
00110     {
00111       ++line_number;
00112     }
00113 
00118     virtual void
00119     end()
00120     {
00121     }
00122   };
00123 
00130   template <typename K, typename P = basic_keyfile_parser<K> >
00131   class basic_keyfile : public keyfile_base
00132   {
00133   private:
00135     typedef typename K::group_name_type group_name_type;
00136 
00138     typedef typename K::key_type key_type;
00139 
00141     typedef typename K::value_type value_type;
00142 
00144     typedef typename K::comment_type comment_type;
00145 
00147     typedef typename K::size_type size_type;
00148 
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 
00211     bool
00212     has_group (group_name_type const& group) const;
00213 
00221     bool
00222     has_key (group_name_type const& group,
00223              key_type const&         key) const;
00224 
00232     void
00233     set_group (group_name_type const&   group,
00234                comment_type const& comment);
00235 
00244     void
00245     set_group (group_name_type const& group,
00246                comment_type const&    comment,
00247                size_type              line);
00248 
00255     comment_type
00256     get_comment (group_name_type const& group) const;
00257 
00265     comment_type
00266     get_comment (group_name_type const& group,
00267                  key_type const& key) const;
00268 
00275     size_type
00276     get_line (group_name_type const& group) const;
00277 
00285     size_type
00286     get_line (group_name_type const& group,
00287               key_type const& key) const;
00288 
00299     template <typename T>
00300     bool
00301     get_value (group_name_type const& group,
00302                key_type const& key,
00303                T&                 value) const
00304     {
00305       log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00306                             << ", key=" << key << std::endl;
00307       const item_type *found_item = find_item(group, key);
00308       if (found_item)
00309         {
00310           value_type const& strval(std::tr1::get<1>(*found_item));
00311           try
00312             {
00313               parse_value(strval, value);
00314               return true;
00315             }
00316           catch (parse_value_error const& e)
00317             {
00318               size_type line = get_line(group, key);
00319               if (line)
00320                 {
00321                   error ep(line, group, key, PASSTHROUGH_LGK, e);
00322                   log_exception_warning(ep);
00323                 }
00324               else
00325                 {
00326                   error ep(group, key, PASSTHROUGH_GK, e);
00327                   log_exception_warning(ep);
00328                 }
00329               return false;
00330             }
00331         }
00332       log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00333       return false;
00334     }
00335 
00348     template <typename T>
00349     bool
00350     get_value (group_name_type const& group,
00351                key_type const& key,
00352                priority           priority,
00353                T&                 value) const
00354     {
00355       bool status = get_value(group, key, value);
00356       check_priority(group, key, priority, status);
00357       return status;
00358     }
00359 
00369     bool
00370     get_locale_string (group_name_type const& group,
00371                        key_type const&        key,
00372                        std::string&           value) const;
00373 
00385     bool
00386     get_locale_string (group_name_type const& group,
00387                        key_type const& key,
00388                        priority           priority,
00389                        std::string&       value) const;
00390 
00401     bool
00402     get_locale_string (group_name_type const& group,
00403                        key_type const& key,
00404                        std::string const& locale,
00405                        std::string&       value) const;
00406 
00420     bool
00421     get_locale_string (group_name_type const& group,
00422                        key_type const& key,
00423                        std::string const& locale,
00424                        priority           priority,
00425                        std::string&       value) const;
00426 
00439     template <typename C>
00440     bool
00441     get_list_value (group_name_type const& group,
00442                     key_type const& key,
00443                     C&                 container) const
00444     {
00445       std::string item_value;
00446       if (get_value(group, key, item_value))
00447         {
00448           string_list items = split_string(item_value,
00449                                            std::string(1, this->separator));
00450           for (string_list::const_iterator pos = items.begin();
00451                pos != items.end();
00452                ++pos
00453                )
00454             {
00455               typename C::value_type tmp;
00456 
00457               try
00458                 {
00459                   parse_value(*pos, tmp);
00460                 }
00461               catch (parse_value_error const& e)
00462                 {
00463                   size_type line = get_line(group, key);
00464                   if (line)
00465                     {
00466                       error ep(line, group, key, PASSTHROUGH_LGK, e);
00467                       log_exception_warning(ep);
00468                     }
00469                   else
00470                     {
00471                       error ep(group, key, PASSTHROUGH_GK, e);
00472                       log_exception_warning(ep);
00473                     }
00474                   return false;
00475                 }
00476 
00477               container.push_back(tmp);
00478             }
00479           return true;
00480         }
00481       return false;
00482     }
00483 
00498     template <typename C>
00499     bool
00500     get_list_value (group_name_type const& group,
00501                     key_type const& key,
00502                     priority           priority,
00503                     C&                 container) const
00504     {
00505       bool status = get_list_value(group, key, container);
00506       check_priority(group, key, priority, status);
00507       return status;
00508     }
00509 
00518     template <typename T>
00519     void
00520     set_value (group_name_type const& group,
00521                key_type const& key,
00522                T const&           value)
00523     {
00524       set_value(group, key, value, comment_type());
00525     }
00526 
00536     template <typename T>
00537     void
00538     set_value (group_name_type const& group,
00539                key_type const& key,
00540                T const&           value,
00541                comment_type const& comment)
00542     {
00543       set_value(group, key, value, comment, 0);
00544     }
00545 
00556     template <typename T>
00557     void
00558     set_value (group_name_type const& group,
00559                key_type const& key,
00560                T const&           value,
00561                comment_type const& comment,
00562                size_type       line)
00563     {
00564       std::ostringstream os;
00565       os.imbue(std::locale::classic());
00566       os << std::boolalpha << value;
00567 
00568       set_group(group, "");
00569       group_type *found_group = find_group(group);
00570       assert (found_group != 0); // should not fail
00571 
00572       item_map_type& items = std::tr1::get<1>(*found_group);
00573 
00574       typename item_map_type::iterator pos = items.find(key);
00575       if (pos != items.end())
00576         items.erase(pos);
00577       items.insert
00578         (typename item_map_type::value_type(key,
00579                                             item_type(key, os.str(), comment, line)));
00580     }
00581 
00591     template <typename I>
00592     void
00593     set_list_value (group_name_type const& group,
00594                     key_type const& key,
00595                     I                  begin,
00596                     I                  end)
00597     {
00598       set_list_value(group, key, begin, end, comment_type());
00599     }
00600 
00611     template <typename I>
00612     void
00613     set_list_value (group_name_type const& group,
00614                     key_type const& key,
00615                     I                  begin,
00616                     I                  end,
00617                     comment_type const& comment)
00618     {
00619       set_list_value (group, key, begin, end, comment, 0);
00620     }
00621 
00633     template <typename I>
00634     void
00635     set_list_value (group_name_type const& group,
00636                     key_type const& key,
00637                     I                  begin,
00638                     I                  end,
00639                     comment_type const& comment,
00640                     size_type       line)
00641     {
00642       std::string strval;
00643 
00644       for (I pos = begin; pos != end; ++ pos)
00645         {
00646           std::ostringstream os;
00647           os.imbue(std::locale::classic());
00648           os << std::boolalpha << *pos;
00649           if (os)
00650             {
00651               strval += os.str();
00652               if (pos + 1 != end)
00653                 strval += this->separator;
00654             }
00655         }
00656 
00657       set_value (group, key, strval, comment, line);
00658     }
00659 
00665     void
00666     remove_group (group_name_type const& group);
00667 
00674     void
00675     remove_key (group_name_type const& group,
00676                 key_type const& key);
00677 
00684     basic_keyfile&
00685     operator += (basic_keyfile const& rhs);
00686 
00694     template <typename _K, typename _P>
00695     friend basic_keyfile<_K, _P>
00696     operator + (basic_keyfile<_K, _P> const& lhs,
00697                 basic_keyfile<_K, _P> const& rhs);
00698 
00706     template <class charT, class traits>
00707     friend
00708     std::basic_istream<charT,traits>&
00709     operator >> (std::basic_istream<charT,traits>& stream,
00710                  basic_keyfile&                          kf)
00711     {
00712       basic_keyfile tmp;
00713       parse_type state;
00714       std::string line;
00715 
00716       state.begin();
00717 
00718       while (std::getline(stream, line))
00719       {
00720         state.parse_line(line);
00721 
00722         // Insert group
00723         if (state.group_set)
00724           {
00725             if (tmp.has_group(state.group))
00726               throw error(state.line_number, DUPLICATE_GROUP, state.group);
00727             else
00728               tmp.set_group(state.group, state.comment, state.line_number);
00729           }
00730 
00731         // Insert item
00732         if (state.key_set && state.value_set)
00733           {
00734             if (tmp.has_key(state.group, state.key))
00735               throw error(state.line_number, state.group, DUPLICATE_KEY, state.key);
00736             else
00737               tmp.set_value(state.group, state.key, state.value, state.comment, state.line_number);
00738           }
00739       }
00740 
00741       state.end();
00742       // TODO: do inserts here as well.
00743 
00744       kf += tmp;
00745 
00746       return stream;
00747     }
00748 
00756     template <class charT, class traits>
00757     friend
00758     std::basic_ostream<charT,traits>&
00759     operator << (std::basic_ostream<charT,traits>& stream,
00760                  basic_keyfile const&                    kf)
00761     {
00762       size_type group_count = 0;
00763 
00764       for (typename group_map_type::const_iterator gp = kf.groups.begin();
00765            gp != kf.groups.end();
00766            ++gp, ++group_count)
00767         {
00768           if (group_count > 0)
00769             stream << '\n';
00770 
00771           group_type const& group = gp->second;
00772           group_name_type const& groupname = std::tr1::get<0>(group);
00773           comment_type const& comment = std::tr1::get<2>(group);
00774 
00775           if (comment.length() > 0)
00776             print_comment(comment, stream);
00777 
00778           stream << '[' << groupname << ']' << '\n';
00779 
00780           item_map_type const& items(std::tr1::get<1>(group));
00781           for (typename item_map_type::const_iterator it = items.begin();
00782                it != items.end();
00783                ++it)
00784             {
00785               item_type const& item = it->second;
00786               key_type const& key(std::tr1::get<0>(item));
00787               value_type const& value(std::tr1::get<1>(item));
00788               comment_type const& comment(std::tr1::get<2>(item));
00789 
00790               if (comment.length() > 0)
00791                 print_comment(comment, stream);
00792 
00793               stream << key << '=' << value << '\n';
00794             }
00795         }
00796 
00797       return stream;
00798     }
00799 
00800   private:
00807     const group_type *
00808     find_group (group_name_type const& group) const;
00809 
00816     group_type *
00817     find_group (group_name_type const& group);
00818 
00826     const item_type *
00827     find_item (group_name_type const& group,
00828                key_type const& key) const;
00829 
00837     item_type *
00838     find_item (group_name_type const& group,
00839                key_type const& key);
00840 
00849     void
00850     check_priority (group_name_type const& group,
00851                     key_type const& key,
00852                     priority           priority,
00853                     bool               valid) const;
00854 
00866     static void
00867     print_comment (comment_type const& comment,
00868                    std::ostream&      stream);
00869 
00871     group_map_type groups;
00873     char           separator;
00874 
00875   public:
00888     template<class C, typename T>
00889     static void
00890     set_object_value (C const&            object,
00891                       T             (C::* method)() const,
00892                       basic_keyfile&            basic_keyfile,
00893                       group_name_type const&  group,
00894                       key_type const&  key)
00895     {
00896       try
00897         {
00898           basic_keyfile.set_value(group, key, (object.*method)());
00899         }
00900       catch (std::runtime_error const& e)
00901         {
00902           throw error(group, key, PASSTHROUGH_GK, e);
00903         }
00904     }
00905 
00918     template<class C, typename T>
00919     static void
00920     set_object_value (C const&            object,
00921                       T const&      (C::* method)() const,
00922                       basic_keyfile&            basic_keyfile,
00923                       group_name_type const&  group,
00924                       key_type const&  key)
00925     {
00926       try
00927         {
00928           basic_keyfile.set_value(group, key, (object.*method)());
00929         }
00930       catch (std::runtime_error const& e)
00931         {
00932           throw error(group, key, PASSTHROUGH_GK, e);
00933         }
00934     }
00935 
00949     template<class C, typename T>
00950     static void
00951     set_object_list_value (C const&            object,
00952                            T             (C::* method)() const,
00953                            basic_keyfile&            basic_keyfile,
00954                            group_name_type const&  group,
00955                            key_type const&  key)
00956     {
00957       try
00958         {
00959           basic_keyfile.set_list_value(group, key,
00960                                  (object.*method)().begin(),
00961                                  (object.*method)().end());
00962         }
00963       catch (std::runtime_error const& e)
00964         {
00965           throw error(group, key, PASSTHROUGH_GK, e);
00966         }
00967     }
00968 
00983     template<class C, typename T>
00984     static void
00985     set_object_list_value (C const&            object,
00986                            T const&      (C::* method)() const,
00987                            basic_keyfile&            basic_keyfile,
00988                            group_name_type const&  group,
00989                            key_type const&  key)
00990     {
00991       try
00992         {
00993           basic_keyfile.set_list_value(group, key,
00994                                  (object.*method)().begin(),
00995                                  (object.*method)().end());
00996         }
00997       catch (std::runtime_error const& e)
00998         {
00999           throw error(group, key, PASSTHROUGH_GK, e);
01000         }
01001     }
01002 
01017     template<class C, typename T>
01018     static void
01019     get_object_value (C&                  object,
01020                       void          (C::* method)(T param),
01021                       basic_keyfile const&      basic_keyfile,
01022                       group_name_type const&  group,
01023                       key_type const&  key,
01024                       basic_keyfile::priority   priority)
01025     {
01026       try
01027         {
01028           T value;
01029           if (basic_keyfile.get_value(group, key, priority, value))
01030             (object.*method)(value);
01031         }
01032       catch (std::runtime_error const& e)
01033         {
01034           size_type line = basic_keyfile.get_line(group, key);
01035           if (line)
01036             throw error(line, group, key, PASSTHROUGH_LGK, e);
01037           else
01038             throw error(group, key, PASSTHROUGH_GK, e);
01039         }
01040     }
01041 
01056     template<class C, typename T>
01057     static void
01058     get_object_value (C&                  object,
01059                       void          (C::* method)(T const& param),
01060                       basic_keyfile const&      basic_keyfile,
01061                       group_name_type const&  group,
01062                       key_type const&  key,
01063                       basic_keyfile::priority   priority)
01064     {
01065       try
01066         {
01067           T value;
01068           if (basic_keyfile.get_value(group, key, priority, value))
01069             (object.*method)(value);
01070         }
01071       catch (std::runtime_error const& e)
01072         {
01073           size_type line = basic_keyfile.get_line(group, key);
01074           if (line)
01075             throw error(line, group, key, PASSTHROUGH_LGK, e);
01076           else
01077             throw error(group, key, PASSTHROUGH_GK, e);
01078         }
01079     }
01080 
01095     template<class C, typename T>
01096     static void
01097     get_object_list_value (C&                  object,
01098                            void          (C::* method)(T param),
01099                            basic_keyfile const&      basic_keyfile,
01100                            group_name_type const&  group,
01101                            key_type const&  key,
01102                            basic_keyfile::priority   priority)
01103     {
01104       try
01105         {
01106           T value;
01107           if (basic_keyfile.get_list_value(group, key, priority, value))
01108             (object.*method)(value);
01109         }
01110       catch (std::runtime_error const& e)
01111         {
01112           size_type line = basic_keyfile.get_line(group, key);
01113           if (line)
01114             throw error(line, group, key, PASSTHROUGH_LGK, e);
01115           else
01116             throw error(group, key, PASSTHROUGH_GK, e);
01117           throw error(basic_keyfile.get_line(group, key),
01118                       group, key, e);
01119         }
01120     }
01121 
01137     template<class C, typename T>
01138     static void
01139     get_object_list_value (C&                  object,
01140                            void          (C::* method)(T const& param),
01141                            basic_keyfile const&      basic_keyfile,
01142                            group_name_type const&  group,
01143                            key_type const&  key,
01144                            basic_keyfile::priority   priority)
01145     {
01146       try
01147         {
01148           T value;
01149           if (basic_keyfile.get_list_value(group, key, priority, value))
01150             (object.*method)(value);
01151         }
01152       catch (std::runtime_error const& e)
01153         {
01154           size_type line = basic_keyfile.get_line(group, key);
01155           if (line)
01156             throw error(line, group, key, PASSTHROUGH_LGK, e);
01157           else
01158             throw error(group, key, PASSTHROUGH_GK, e);
01159           throw error(basic_keyfile.get_line(group, key),
01160                       group, key, e);
01161         }
01162     }
01163   };
01164 
01165 }
01166 
01167 #include <sbuild/sbuild-basic-keyfile.tcc>
01168 
01169 #endif /* SBUILD_BASIC_KEYFILE_H */
01170 
01171 /*
01172  * Local Variables:
01173  * mode:C++
01174  * End:
01175  */

Generated on Sun Jul 8 21:23:22 2007 for sbuild by  doxygen 1.5.2