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     enum error_code
00076       {
00077         BAD_FILE,          
00078         DEPRECATED_KEY,    
00079         DEPRECATED_KEY_NL, 
00080         DISALLOWED_KEY,    
00081         DISALLOWED_KEY_NL, 
00082         DUPLICATE_GROUP,   
00083         DUPLICATE_KEY,     
00084         INVALID_GROUP,     
00085         INVALID_LINE,      
00086         MISSING_KEY,       
00087         MISSING_KEY_NL,    
00088         NO_GROUP,          
00089         NO_KEY,            
00090         OBSOLETE_KEY,      
00091         OBSOLETE_KEY_NL,   
00092         PASSTHROUGH_G,     
00093         PASSTHROUGH_GK,    
00094         PASSTHROUGH_LG,    
00095         PASSTHROUGH_LGK    
00096       };
00097 
00099     typedef parse_error<error_code> error;
00100 
00102     keyfile ();
00103 
00109     keyfile (std::string const& file);
00110 
00116     keyfile (std::istream& stream);
00117 
00119     virtual ~keyfile ();
00120 
00127     string_list
00128     get_groups () const;
00129 
00137     string_list
00138     get_keys (std::string const& group) const;
00139 
00146     bool
00147     has_group (std::string const& group) const;
00148 
00156     bool
00157     has_key (std::string const& group,
00158              std::string const& key) const;
00159 
00167     void
00168     set_group (std::string const& group,
00169                std::string const& comment);
00170 
00179     void
00180     set_group (std::string const& group,
00181                std::string const& comment,
00182                unsigned int       line);
00183 
00190     std::string
00191     get_comment (std::string const& group) const;
00192 
00200     std::string
00201     get_comment (std::string const& group,
00202                  std::string const& key) const;
00203 
00210     unsigned int
00211     get_line (std::string const& group) const;
00212 
00220     unsigned int
00221     get_line (std::string const& group,
00222               std::string const& key) const;
00223 
00234     template <typename T>
00235     bool
00236     get_value (std::string const& group,
00237                std::string const& key,
00238                T&                 value) const
00239     {
00240       log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00241                             << ", key=" << key << std::endl;
00242       const item_type *found_item = find_item(group, key);
00243       if (found_item)
00244         {
00245           std::string const& strval(std::tr1::get<1>(*found_item));
00246           try
00247             {
00248               parse_value(strval, value);
00249               return true;
00250             }
00251           catch (parse_value_error const& e)
00252             {
00253               unsigned int line = get_line(group, key);
00254               if (line)
00255                 {
00256                   error ep(line, group, key, PASSTHROUGH_LGK, e);
00257                   log_exception_warning(ep);
00258                 }
00259               else
00260                 {
00261                   error ep(group, key, PASSTHROUGH_GK, e);
00262                   log_exception_warning(ep);
00263                 }
00264               return false;
00265             }
00266         }
00267       log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00268       return false;
00269     }
00270 
00283     template <typename T>
00284     bool
00285     get_value (std::string const& group,
00286                std::string const& key,
00287                priority           priority,
00288                T&                 value) const
00289     {
00290       bool status = get_value(group, key, value);
00291       check_priority(group, key, priority, status);
00292       return status;
00293     }
00294 
00304     bool
00305     get_locale_string (std::string const& group,
00306                        std::string const& key,
00307                        std::string&       value) const;
00308 
00320     bool
00321     get_locale_string (std::string const& group,
00322                        std::string const& key,
00323                        priority           priority,
00324                        std::string&       value) const;
00325 
00336     bool
00337     get_locale_string (std::string const& group,
00338                        std::string const& key,
00339                        std::string const& locale,
00340                        std::string&       value) const;
00341 
00355     bool
00356     get_locale_string (std::string const& group,
00357                        std::string const& key,
00358                        std::string const& locale,
00359                        priority           priority,
00360                        std::string&       value) const;
00361 
00374     template <typename C>
00375     bool
00376     get_list_value (std::string const& group,
00377                     std::string const& key,
00378                     C&                 container) const
00379     {
00380       std::string item_value;
00381       if (get_value(group, key, item_value))
00382         {
00383           string_list items = split_string(item_value,
00384                                            std::string(1, this->separator));
00385           for (string_list::const_iterator pos = items.begin();
00386                pos != items.end();
00387                ++pos
00388                )
00389             {
00390               typename C::value_type tmp;
00391 
00392               try
00393                 {
00394                   parse_value(*pos, tmp);
00395                 }
00396               catch (parse_value_error const& e)
00397                 {
00398                   unsigned int line = get_line(group, key);
00399                   if (line)
00400                     {
00401                       error ep(line, group, key, PASSTHROUGH_LGK, e);
00402                       log_exception_warning(ep);
00403                     }
00404                   else
00405                     {
00406                       error ep(group, key, PASSTHROUGH_GK, e);
00407                       log_exception_warning(ep);
00408                     }
00409                   return false;
00410                 }
00411 
00412               container.push_back(tmp);
00413             }
00414           return true;
00415         }
00416       return false;
00417     }
00418 
00433     template <typename C>
00434     bool
00435     get_list_value (std::string const& group,
00436                     std::string const& key,
00437                     priority           priority,
00438                     C&                 container) const
00439     {
00440       bool status = get_list_value(group, key, container);
00441       check_priority(group, key, priority, status);
00442       return status;
00443     }
00444 
00453     template <typename T>
00454     void
00455     set_value (std::string const& group,
00456                std::string const& key,
00457                T const&           value)
00458     {
00459       set_value(group, key, value, std::string());
00460     }
00461 
00471     template <typename T>
00472     void
00473     set_value (std::string const& group,
00474                std::string const& key,
00475                T const&           value,
00476                std::string const& comment)
00477     {
00478       set_value(group, key, value, comment, 0);
00479     }
00480 
00491     template <typename T>
00492     void
00493     set_value (std::string const& group,
00494                std::string const& key,
00495                T const&           value,
00496                std::string const& comment,
00497                unsigned int       line)
00498     {
00499       std::ostringstream os;
00500       os.imbue(std::locale("C"));
00501       os << std::boolalpha << value;
00502 
00503       set_group(group, "");
00504       group_type *found_group = find_group(group);
00505       assert (found_group != 0); // should not fail
00506 
00507       item_map_type& items = std::tr1::get<1>(*found_group);
00508 
00509       item_map_type::iterator pos = items.find(key);
00510       if (pos != items.end())
00511         items.erase(pos);
00512       items.insert
00513         (item_map_type::value_type(key,
00514                                    item_type(key, os.str(), comment, line)));
00515     }
00516 
00526     template <typename I>
00527     void
00528     set_list_value (std::string const& group,
00529                     std::string const& key,
00530                     I                  begin,
00531                     I                  end)
00532     {
00533       set_list_value(group, key, begin, end, std::string());
00534     }
00535 
00546     template <typename I>
00547     void
00548     set_list_value (std::string const& group,
00549                     std::string const& key,
00550                     I                  begin,
00551                     I                  end,
00552                     std::string const& comment)
00553     {
00554       set_list_value (group, key, begin, end, comment, 0);
00555     }
00556 
00568     template <typename I>
00569     void
00570     set_list_value (std::string const& group,
00571                     std::string const& key,
00572                     I                  begin,
00573                     I                  end,
00574                     std::string const& comment,
00575                     unsigned int       line)
00576     {
00577       std::string strval;
00578 
00579       for (I pos = begin; pos != end; ++ pos)
00580         {
00581           std::ostringstream os;
00582           os.imbue(std::locale("C"));
00583           os << std::boolalpha << *pos;
00584           if (os)
00585             {
00586               strval += os.str();
00587               if (pos + 1 != end)
00588                 strval += this->separator;
00589             }
00590         }
00591 
00592       set_value (group, key, strval, comment, line);
00593     }
00594 
00600     void
00601     remove_group (std::string const& group);
00602 
00609     void
00610     remove_key (std::string const& group,
00611                 std::string const& key);
00612 
00619     keyfile&
00620     operator += (keyfile const& rhs);
00621 
00629     friend keyfile
00630     operator + (keyfile const& lhs,
00631                 keyfile const& rhs);
00632 
00636     template <class charT, class traits>
00637     friend
00638     std::basic_istream<charT,traits>&
00639     operator >> (std::basic_istream<charT,traits>& stream,
00640                  keyfile&                          kf)
00641     {
00642       keyfile tmp;
00643       size_t linecount = 0;
00644       std::string line;
00645       std::string group;
00646       std::string comment;
00647       std::string key;
00648       std::string value;
00649 
00650       while (std::getline(stream, line))
00651       {
00652         linecount++;
00653 
00654         if (line.length() == 0)
00655           {
00656             // Empty line; do nothing.
00657           }
00658         else if (line[0] == '#') // Comment line
00659           {
00660             if (!comment.empty())
00661               comment += '\n';
00662             comment += line.substr(1);
00663           }
00664         else if (line[0] == '[') // Group
00665           {
00666             std::string::size_type fpos = line.find_first_of(']');
00667             std::string::size_type lpos = line.find_last_of(']');
00668             if (fpos == std::string::npos || lpos == std::string::npos ||
00669                 fpos != lpos)
00670               throw error(linecount, INVALID_GROUP, line);
00671             group = line.substr(1, fpos - 1);
00672 
00673             if (group.length() == 0)
00674               throw error(linecount, INVALID_GROUP, line);
00675 
00676             // Insert group
00677             if (tmp.has_group(group))
00678               throw error(linecount, DUPLICATE_GROUP, group);
00679             else
00680               tmp.set_group(group, comment, linecount);
00681             comment.clear();
00682           }
00683         else // Item
00684           {
00685             std::string::size_type pos = line.find_first_of('=');
00686             if (pos == std::string::npos)
00687               throw error(linecount, INVALID_LINE, line);
00688             if (pos == 0)
00689               throw error(linecount, NO_KEY, line);
00690             key = line.substr(0, pos);
00691             if (pos == line.length() - 1)
00692               value = "";
00693             else
00694               value = line.substr(pos + 1);
00695 
00696             // No group specified
00697             if (group.empty())
00698               throw error(linecount, NO_GROUP, line);
00699 
00700             // Insert item
00701             if (tmp.has_key(group, key))
00702               throw error(linecount, group, DUPLICATE_KEY, key);
00703             else
00704               tmp.set_value(group, key, value, comment, linecount);
00705             comment.clear();
00706           }
00707       }
00708 
00709       kf += tmp;
00710 
00711       return stream;
00712     }
00713 
00717     template <class charT, class traits>
00718     friend
00719     std::basic_ostream<charT,traits>&
00720     operator << (std::basic_ostream<charT,traits>& stream,
00721                  keyfile const&                    kf)
00722     {
00723       unsigned int group_count = 0;
00724 
00725       for (group_map_type::const_iterator gp = kf.groups.begin();
00726            gp != kf.groups.end();
00727            ++gp, ++group_count)
00728         {
00729           if (group_count > 0)
00730             stream << '\n';
00731 
00732           group_type const& group = gp->second;
00733           std::string const& groupname = std::tr1::get<0>(group);
00734           std::string const& comment = std::tr1::get<2>(group);
00735 
00736           if (comment.length() > 0)
00737             print_comment(comment, stream);
00738 
00739           stream << '[' << groupname << ']' << '\n';
00740 
00741           item_map_type const& items(std::tr1::get<1>(group));
00742           for (item_map_type::const_iterator it = items.begin();
00743                it != items.end();
00744                ++it)
00745             {
00746               item_type const& item = it->second;
00747               std::string const& key(std::tr1::get<0>(item));
00748               std::string const& value(std::tr1::get<1>(item));
00749               std::string const& comment(std::tr1::get<2>(item));
00750 
00751               if (comment.length() > 0)
00752                 print_comment(comment, stream);
00753 
00754               stream << key << '=' << value << '\n';
00755             }
00756         }
00757 
00758       return stream;
00759     }
00760 
00761   private:
00768     const group_type *
00769     find_group (std::string const& group) const;
00770 
00777     group_type *
00778     find_group (std::string const& group);
00779 
00787     const item_type *
00788     find_item (std::string const& group,
00789                std::string const& key) const;
00790 
00798     item_type *
00799     find_item (std::string const& group,
00800                std::string const& key);
00801 
00810     void
00811     check_priority (std::string const& group,
00812                     std::string const& key,
00813                     priority           priority,
00814                     bool               valid) const;
00815 
00823     static void
00824     print_comment (std::string const& comment,
00825                    std::ostream&      stream);
00826 
00828     group_map_type groups;
00830     char           separator;
00831 
00832   public:
00845     template<class C, typename T>
00846     static void
00847     set_object_value (C const&            object,
00848                       T             (C::* method)() const,
00849                       keyfile&            keyfile,
00850                       std::string const&  group,
00851                       std::string const&  key)
00852     {
00853       try
00854         {
00855           keyfile.set_value(group, key, (object.*method)());
00856         }
00857       catch (std::runtime_error const& e)
00858         {
00859           throw error(group, key, PASSTHROUGH_GK, e);
00860         }
00861     }
00862 
00875     template<class C, typename T>
00876     static void
00877     set_object_value (C const&            object,
00878                       T const&      (C::* method)() const,
00879                       keyfile&            keyfile,
00880                       std::string const&  group,
00881                       std::string const&  key)
00882     {
00883       try
00884         {
00885           keyfile.set_value(group, key, (object.*method)());
00886         }
00887       catch (std::runtime_error const& e)
00888         {
00889           throw error(group, key, PASSTHROUGH_GK, e);
00890         }
00891     }
00892 
00906     template<class C, typename T>
00907     static void
00908     set_object_list_value (C const&            object,
00909                            T             (C::* method)() const,
00910                            keyfile&            keyfile,
00911                            std::string const&  group,
00912                            std::string const&  key)
00913     {
00914       try
00915         {
00916           keyfile.set_list_value(group, key,
00917                                  (object.*method)().begin(),
00918                                  (object.*method)().end());
00919         }
00920       catch (std::runtime_error const& e)
00921         {
00922           throw error(group, key, PASSTHROUGH_GK, e);
00923         }
00924     }
00925 
00940     template<class C, typename T>
00941     static void
00942     set_object_list_value (C const&            object,
00943                            T const&      (C::* method)() const,
00944                            keyfile&            keyfile,
00945                            std::string const&  group,
00946                            std::string const&  key)
00947     {
00948       try
00949         {
00950           keyfile.set_list_value(group, key,
00951                                  (object.*method)().begin(),
00952                                  (object.*method)().end());
00953         }
00954       catch (std::runtime_error const& e)
00955         {
00956           throw error(group, key, PASSTHROUGH_GK, e);
00957         }
00958     }
00959 
00974     template<class C, typename T>
00975     static void
00976     get_object_value (C&                  object,
00977                       void          (C::* method)(T param),
00978                       keyfile const&      keyfile,
00979                       std::string const&  group,
00980                       std::string const&  key,
00981                       keyfile::priority   priority)
00982     {
00983       try
00984         {
00985           T value;
00986           if (keyfile.get_value(group, key, priority, value))
00987             (object.*method)(value);
00988         }
00989       catch (std::runtime_error const& e)
00990         {
00991           unsigned int line = keyfile.get_line(group, key);
00992           if (line)
00993             throw error(line, group, key, PASSTHROUGH_LGK, e);
00994           else
00995             throw error(group, key, PASSTHROUGH_GK, e);
00996         }
00997     }
00998 
01013     template<class C, typename T>
01014     static void
01015     get_object_value (C&                  object,
01016                       void          (C::* method)(T const& param),
01017                       keyfile const&      keyfile,
01018                       std::string const&  group,
01019                       std::string const&  key,
01020                       keyfile::priority   priority)
01021     {
01022       try
01023         {
01024           T value;
01025           if (keyfile.get_value(group, key, priority, value))
01026             (object.*method)(value);
01027         }
01028       catch (std::runtime_error const& e)
01029         {
01030           unsigned int line = keyfile.get_line(group, key);
01031           if (line)
01032             throw error(line, group, key, PASSTHROUGH_LGK, e);
01033           else
01034             throw error(group, key, PASSTHROUGH_GK, e);
01035         }
01036     }
01037 
01052     template<class C, typename T>
01053     static void
01054     get_object_list_value (C&                  object,
01055                            void          (C::* method)(T param),
01056                            keyfile const&      keyfile,
01057                            std::string const&  group,
01058                            std::string const&  key,
01059                            keyfile::priority   priority)
01060     {
01061       try
01062         {
01063           T value;
01064           if (keyfile.get_list_value(group, key, priority, value))
01065             (object.*method)(value);
01066         }
01067       catch (std::runtime_error const& e)
01068         {
01069           unsigned int line = keyfile.get_line(group, key);
01070           if (line)
01071             throw error(line, group, key, PASSTHROUGH_LGK, e);
01072           else
01073             throw error(group, key, PASSTHROUGH_GK, e);
01074           throw error(keyfile.get_line(group, key),
01075                       group, key, e);
01076         }
01077     }
01078 
01094     template<class C, typename T>
01095     static void
01096     get_object_list_value (C&                  object,
01097                            void          (C::* method)(T const& param),
01098                            keyfile const&      keyfile,
01099                            std::string const&  group,
01100                            std::string const&  key,
01101                            keyfile::priority   priority)
01102     {
01103       try
01104         {
01105           T value;
01106           if (keyfile.get_list_value(group, key, priority, value))
01107             (object.*method)(value);
01108         }
01109       catch (std::runtime_error const& e)
01110         {
01111           unsigned int line = keyfile.get_line(group, key);
01112           if (line)
01113             throw error(line, group, key, PASSTHROUGH_LGK, e);
01114           else
01115             throw error(group, key, PASSTHROUGH_GK, e);
01116           throw error(keyfile.get_line(group, key),
01117                       group, key, e);
01118         }
01119     }
01120   };
01121 
01122 }
01123 
01124 #endif /* SBUILD_KEYFILE_H */
01125 
01126 /*
01127  * Local Variables:
01128  * mode:C++
01129  * End:
01130  */

Generated on Thu Jul 20 16:35:17 2006 for schroot by  doxygen 1.4.7