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         DISALLOWED_KEY,     
00079         DISALLOWED_KEY_NL,  
00080         DUPLICATE_GROUP,    
00081         DUPLICATE_KEY,      
00082         INVALID_GROUP,      
00083         INVALID_LINE,       
00084         MISSING_KEY,        
00085         NO_GROUP,           
00086         NO_KEY,             
00087         PASSTHROUGH_GK,     
00088         PASSTHROUGH_LGK     
00089       };
00090 
00092     typedef parse_error<error_code> error;
00093 
00095     keyfile ();
00096 
00102     keyfile (std::string const& file);
00103 
00109     keyfile (std::istream& stream);
00110 
00112     virtual ~keyfile ();
00113 
00120     string_list
00121     get_groups () const;
00122 
00130     string_list
00131     get_keys (std::string const& group) const;
00132 
00139     bool
00140     has_group (std::string const& group) const;
00141 
00149     bool
00150     has_key (std::string const& group,
00151              std::string const& key) const;
00152 
00160     void
00161     set_group (std::string const& group,
00162                std::string const& comment);
00163 
00164   private:
00173     void
00174     set_group (std::string const& group,
00175                std::string const& comment,
00176                unsigned int       line);
00177 
00178   public:
00185     std::string
00186     get_comment (std::string const& group) const;
00187 
00195     std::string
00196     get_comment (std::string const& group,
00197                  std::string const& key) const;
00198 
00205     unsigned int
00206     get_line (std::string const& group) const;
00207 
00215     unsigned int
00216     get_line (std::string const& group,
00217               std::string const& key) const;
00218 
00229     template <typename T>
00230     bool
00231     get_value (std::string const& group,
00232                std::string const& key,
00233                T&                 value) const
00234     {
00235       log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00236                             << ", key=" << key << std::endl;
00237       const item_type *found_item = find_item(group, key);
00238       if (found_item)
00239         {
00240           std::string const& strval(std::tr1::get<1>(*found_item));
00241           try
00242             {
00243               parse_value(strval, value);
00244               return true;
00245             }
00246           catch (parse_value_error const& e)
00247             {
00248               unsigned int line = get_line(group, key);
00249               if (line)
00250                 {
00251                   error ep(line, group, key, PASSTHROUGH_LGK, e.what());
00252                   log_warning() << ep.what() << std::endl;
00253                 }
00254               else
00255                 {
00256                   error ep(group, key, PASSTHROUGH_GK, e.what());
00257                   log_warning() << ep.what() << std::endl;
00258                 }
00259               return false;
00260             }
00261         }
00262       log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00263       return false;
00264     }
00265 
00278     template <typename T>
00279     bool
00280     get_value (std::string const& group,
00281                std::string const& key,
00282                priority           priority,
00283                T&                 value) const
00284     {
00285       bool status = get_value(group, key, value);
00286       check_priority(group, key, priority, status);
00287       return status;
00288     }
00289 
00299     bool
00300     get_locale_string (std::string const& group,
00301                        std::string const& key,
00302                        std::string&       value) const;
00303 
00315     bool
00316     get_locale_string (std::string const& group,
00317                        std::string const& key,
00318                        priority           priority,
00319                        std::string&       value) const;
00320 
00331     bool
00332     get_locale_string (std::string const& group,
00333                        std::string const& key,
00334                        std::string const& locale,
00335                        std::string&       value) const;
00336 
00350     bool
00351     get_locale_string (std::string const& group,
00352                        std::string const& key,
00353                        std::string const& locale,
00354                        priority           priority,
00355                        std::string&       value) const;
00356 
00369     template <typename C>
00370     bool
00371     get_list_value (std::string const& group,
00372                     std::string const& key,
00373                     C&                 container) const
00374     {
00375       std::string item_value;
00376       if (get_value(group, key, item_value))
00377         {
00378           string_list items = split_string(item_value,
00379                                            std::string(1, this->separator));
00380           for (string_list::const_iterator pos = items.begin();
00381                pos != items.end();
00382                ++pos
00383                )
00384             {
00385               typename C::value_type tmp;
00386 
00387               try
00388                 {
00389                   parse_value(*pos, tmp);
00390                 }
00391               catch (parse_value_error const& e)
00392                 {
00393                   unsigned int line = get_line(group, key);
00394                   if (line)
00395                     {
00396                       error ep(line, group, key, PASSTHROUGH_LGK, e.what());
00397                       log_warning() << ep.what() << std::endl;
00398                     }
00399                   else
00400                     {
00401                       error ep(group, key, PASSTHROUGH_GK, e.what());
00402                       log_warning() << ep.what() << std::endl;
00403                     }
00404                   return false;
00405                 }
00406 
00407               container.push_back(tmp);
00408             }
00409           return true;
00410         }
00411       return false;
00412     }
00413 
00428     template <typename C>
00429     bool
00430     get_list_value (std::string const& group,
00431                     std::string const& key,
00432                     priority           priority,
00433                     C&                 container) const
00434     {
00435       bool status = get_list_value(group, key, container);
00436       check_priority(group, key, priority, status);
00437       return status;
00438     }
00439 
00448     template <typename T>
00449     void
00450     set_value (std::string const& group,
00451                std::string const& key,
00452                T const&           value)
00453     {
00454       set_value(group, key, value, std::string());
00455     }
00456 
00466     template <typename T>
00467     void
00468     set_value (std::string const& group,
00469                std::string const& key,
00470                T const&           value,
00471                std::string const& comment)
00472     {
00473       std::ostringstream os;
00474       os.imbue(std::locale("C"));
00475       os << std::boolalpha << value;
00476 
00477       set_value(group, key, os.str(), comment, 0);
00478     }
00479 
00480   private:
00491     void
00492     set_value (std::string const& group,
00493                std::string const& key,
00494                std::string const& value,
00495                std::string const& comment,
00496                unsigned int       line)
00497     {
00498       set_group(group, "");
00499       group_type *found_group = find_group(group);
00500       assert (found_group != 0); // should not fail
00501 
00502       item_map_type& items = std::tr1::get<1>(*found_group);
00503 
00504       item_map_type::iterator pos = items.find(key);
00505       if (pos != items.end())
00506         items.erase(pos);
00507       items.insert
00508         (item_map_type::value_type(key,
00509                                    item_type(key, value, comment, line)));
00510     }
00511 
00512   public:
00522     template <typename I>
00523     void
00524     set_list_value (std::string const& group,
00525                     std::string const& key,
00526                     I                  begin,
00527                     I                  end)
00528     {
00529       set_list_value(group, key, begin, end, std::string());
00530     }
00531 
00542     template <typename I>
00543     void
00544     set_list_value (std::string const& group,
00545                     std::string const& key,
00546                     I                  begin,
00547                     I                  end,
00548                     std::string const& comment)
00549     {
00550       std::string strval;
00551 
00552       for (I pos = begin; pos != end; ++ pos)
00553         {
00554           std::ostringstream os;
00555           os.imbue(std::locale("C"));
00556           os << std::boolalpha << *pos;
00557           if (os)
00558             {
00559               strval += os.str();
00560               if (pos + 1 != end)
00561                 strval += this->separator;
00562             }
00563         }
00564 
00565       set_value (group, key, strval, comment);
00566     }
00567 
00573     void
00574     remove_group (std::string const& group);
00575 
00582     void
00583     remove_key (std::string const& group,
00584                 std::string const& key);
00585 
00592     keyfile&
00593     operator += (keyfile const& rhs);
00594 
00602     friend keyfile
00603     operator + (keyfile const& lhs,
00604                 keyfile const& rhs);
00605 
00609     template <class charT, class traits>
00610     friend
00611     std::basic_istream<charT,traits>&
00612     operator >> (std::basic_istream<charT,traits>& stream,
00613                  keyfile&                          kf)
00614     {
00615       keyfile tmp;
00616       size_t linecount = 0;
00617       std::string line;
00618       std::string group;
00619       std::string comment;
00620       std::string key;
00621       std::string value;
00622 
00623       while (std::getline(stream, line))
00624       {
00625         linecount++;
00626 
00627         if (line.length() == 0)
00628           {
00629             // Empty line; do nothing.
00630           }
00631         else if (line[0] == '#') // Comment line
00632           {
00633             if (!comment.empty())
00634               comment += '\n';
00635             comment += line.substr(1);
00636           }
00637         else if (line[0] == '[') // Group
00638           {
00639             std::string::size_type fpos = line.find_first_of(']');
00640             std::string::size_type lpos = line.find_last_of(']');
00641             if (fpos == std::string::npos || lpos == std::string::npos ||
00642                 fpos != lpos)
00643               {
00644                 throw error(linecount, INVALID_GROUP, line);
00645               }
00646             group = line.substr(1, fpos - 1);
00647 
00648             if (group.length() == 0)
00649               {
00650                 throw error(linecount, INVALID_GROUP, line);
00651               }
00652 
00653             // Insert group
00654             if (tmp.has_group(group))
00655               {
00656                 error e(linecount, DUPLICATE_GROUP, group);
00657                 log_warning() << e.what() << std::endl;
00658               }
00659             else
00660               tmp.set_group(group, comment, linecount);
00661             comment.clear();
00662           }
00663         else // Item
00664           {
00665             std::string::size_type pos = line.find_first_of('=');
00666             if (pos == std::string::npos)
00667               {
00668                 throw error(linecount, INVALID_LINE, line);
00669               }
00670             if (pos == 0)
00671               {
00672                 throw error(linecount, NO_KEY, line);
00673               }
00674             key = line.substr(0, pos);
00675             if (pos == line.length() - 1)
00676               value = "";
00677             else
00678               value = line.substr(pos + 1);
00679 
00680             // No group specified
00681             if (group.empty())
00682               {
00683                 throw error(linecount, NO_GROUP, line);
00684               }
00685 
00686             // Insert item
00687             if (tmp.has_key(group, key))
00688               {
00689                 error e(linecount, group, DUPLICATE_KEY, key);
00690                 log_warning() << e.what() << std::endl;
00691               }
00692             else
00693               tmp.set_value(group, key, value, comment, linecount);
00694             comment.clear();
00695           }
00696       }
00697 
00698       kf += tmp;
00699 
00700       return stream;
00701     }
00702 
00706     template <class charT, class traits>
00707     friend
00708     std::basic_ostream<charT,traits>&
00709     operator << (std::basic_ostream<charT,traits>& stream,
00710                  keyfile const&                    kf)
00711     {
00712       unsigned int group_count = 0;
00713 
00714       for (group_map_type::const_iterator gp = kf.groups.begin();
00715            gp != kf.groups.end();
00716            ++gp, ++group_count)
00717         {
00718           if (group_count > 0)
00719             stream << '\n';
00720 
00721           group_type const& group = gp->second;
00722           std::string const& groupname = std::tr1::get<0>(group);
00723           std::string const& comment = std::tr1::get<2>(group);
00724 
00725           if (comment.length() > 0)
00726             print_comment(comment, stream);
00727 
00728           stream << '[' << groupname << ']' << '\n';
00729 
00730           item_map_type const& items(std::tr1::get<1>(group));
00731           for (item_map_type::const_iterator it = items.begin();
00732                it != items.end();
00733                ++it)
00734             {
00735               item_type const& item = it->second;
00736               std::string const& key(std::tr1::get<0>(item));
00737               std::string const& value(std::tr1::get<1>(item));
00738               std::string const& comment(std::tr1::get<2>(item));
00739 
00740               if (comment.length() > 0)
00741                 print_comment(comment, stream);
00742 
00743               stream << key << '=' << value << '\n';
00744             }
00745         }
00746 
00747       return stream;
00748     }
00749 
00750   private:
00757     const group_type *
00758     find_group (std::string const& group) const;
00759 
00766     group_type *
00767     find_group (std::string const& group);
00768 
00776     const item_type *
00777     find_item (std::string const& group,
00778                std::string const& key) const;
00779 
00787     item_type *
00788     find_item (std::string const& group,
00789                std::string const& key);
00790 
00799     void
00800     check_priority (std::string const& group,
00801                     std::string const& key,
00802                     priority           priority,
00803                     bool               valid) const;
00804 
00812     static void
00813     print_comment (std::string const& comment,
00814                    std::ostream&      stream);
00815 
00817     group_map_type groups;
00819     char           separator;
00820 
00821   public:
00834     template<class C, typename T>
00835     static void
00836     set_object_value (C const&            object,
00837                       T             (C::* method)() const,
00838                       keyfile&            keyfile,
00839                       std::string const&  group,
00840                       std::string const&  key)
00841     {
00842       try
00843         {
00844           keyfile.set_value(group, key, (object.*method)());
00845         }
00846       catch (std::runtime_error const& e)
00847         {
00848           throw error(group, key, PASSTHROUGH_GK, e.what());
00849         }
00850     }
00851 
00864     template<class C, typename T>
00865     static void
00866     set_object_value (C const&            object,
00867                       T const&      (C::* method)() const,
00868                       keyfile&            keyfile,
00869                       std::string const&  group,
00870                       std::string const&  key)
00871     {
00872       try
00873         {
00874           keyfile.set_value(group, key, (object.*method)());
00875         }
00876       catch (std::runtime_error const& e)
00877         {
00878           throw error(group, key, PASSTHROUGH_GK, e.what());
00879         }
00880     }
00881 
00895     template<class C, typename T>
00896     static void
00897     set_object_list_value (C const&            object,
00898                            T             (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 (std::runtime_error const& e)
00910         {
00911           throw error(group, key, PASSTHROUGH_GK, e.what());
00912         }
00913     }
00914 
00929     template<class C, typename T>
00930     static void
00931     set_object_list_value (C const&            object,
00932                            T const&      (C::* method)() const,
00933                            keyfile&            keyfile,
00934                            std::string const&  group,
00935                            std::string const&  key)
00936     {
00937       try
00938         {
00939           keyfile.set_list_value(group, key,
00940                                  (object.*method)().begin(),
00941                                  (object.*method)().end());
00942         }
00943       catch (std::runtime_error const& e)
00944         {
00945           throw error(group, key, PASSTHROUGH_GK, e.what());
00946         }
00947     }
00948 
00963     template<class C, typename T>
00964     static void
00965     get_object_value (C&                  object,
00966                       void          (C::* method)(T param),
00967                       keyfile const&      keyfile,
00968                       std::string const&  group,
00969                       std::string const&  key,
00970                       keyfile::priority   priority)
00971     {
00972       T value;
00973       if (keyfile.get_value(group, key, priority, value))
00974         {
00975           try
00976             {
00977               (object.*method)(value);
00978             }
00979           catch (std::runtime_error const& e)
00980             {
00981               unsigned int line = keyfile.get_line(group, key);
00982               if (line)
00983                 throw error(line, group, key, PASSTHROUGH_LGK, e.what());
00984               else
00985                 throw error(group, key, PASSTHROUGH_GK, e.what());
00986             }
00987         }
00988     }
00989 
01004     template<class C, typename T>
01005     static void
01006     get_object_value (C&                  object,
01007                       void          (C::* method)(T const& param),
01008                       keyfile const&      keyfile,
01009                       std::string const&  group,
01010                       std::string const&  key,
01011                       keyfile::priority   priority)
01012     {
01013       T value;
01014       if (keyfile.get_value(group, key, priority, value))
01015         {
01016           try
01017             {
01018               (object.*method)(value);
01019             }
01020           catch (std::runtime_error const& e)
01021             {
01022               unsigned int line = keyfile.get_line(group, key);
01023               if (line)
01024                 throw error(line, group, key, PASSTHROUGH_LGK, e.what());
01025               else
01026                 throw error(group, key, PASSTHROUGH_GK, e.what());
01027               throw error(keyfile.get_line(group, key),
01028                           group, key, e);
01029             }
01030         }
01031     }
01032 
01047     template<class C, typename T>
01048     static void
01049     get_object_list_value (C&                  object,
01050                            void          (C::* method)(T 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 (std::runtime_error const& e)
01064             {
01065               unsigned int line = keyfile.get_line(group, key);
01066               if (line)
01067                 throw error(line, group, key, PASSTHROUGH_LGK, e.what());
01068               else
01069                 throw error(group, key, PASSTHROUGH_GK, e.what());
01070               throw error(keyfile.get_line(group, key),
01071                           group, key, e);
01072             }
01073         }
01074     }
01075 
01091     template<class C, typename T>
01092     static void
01093     get_object_list_value (C&                  object,
01094                            void          (C::* method)(T const& param),
01095                            keyfile const&      keyfile,
01096                            std::string const&  group,
01097                            std::string const&  key,
01098                            keyfile::priority   priority)
01099     {
01100       T value;
01101       if (keyfile.get_list_value(group, key, priority, value))
01102         {
01103           try
01104             {
01105               (object.*method)(value);
01106             }
01107           catch (std::runtime_error const& e)
01108             {
01109               unsigned int line = keyfile.get_line(group, key);
01110               if (line)
01111                 throw error(line, group, key, PASSTHROUGH_LGK, e.what());
01112               else
01113                 throw error(group, key, PASSTHROUGH_GK, e.what());
01114               throw error(keyfile.get_line(group, key),
01115                           group, key, e);
01116             }
01117         }
01118     }
01119   };
01120 
01121 }
01122 
01123 #endif /* SBUILD_KEYFILE_H */
01124 
01125 /*
01126  * Local Variables:
01127  * mode:C++
01128  * End:
01129  */

Generated on Fri Jul 14 19:52:17 2006 for schroot by  doxygen 1.4.7