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::classic());
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::classic());
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 
00640     template <class charT, class traits>
00641     friend
00642     std::basic_istream<charT,traits>&
00643     operator >> (std::basic_istream<charT,traits>& stream,
00644                  keyfile&                          kf)
00645     {
00646       keyfile tmp;
00647       size_t linecount = 0;
00648       std::string line;
00649       std::string group;
00650       std::string comment;
00651       std::string key;
00652       std::string value;
00653 
00654       while (std::getline(stream, line))
00655       {
00656         linecount++;
00657 
00658         if (line.length() == 0)
00659           {
00660             // Empty line; do nothing.
00661           }
00662         else if (line[0] == '#') // Comment line
00663           {
00664             if (!comment.empty())
00665               comment += '\n';
00666             comment += line.substr(1);
00667           }
00668         else if (line[0] == '[') // Group
00669           {
00670             std::string::size_type fpos = line.find_first_of(']');
00671             std::string::size_type lpos = line.find_last_of(']');
00672             if (fpos == std::string::npos || lpos == std::string::npos ||
00673                 fpos != lpos)
00674               throw error(linecount, INVALID_GROUP, line);
00675             group = line.substr(1, fpos - 1);
00676 
00677             if (group.length() == 0)
00678               throw error(linecount, INVALID_GROUP, line);
00679 
00680             // Insert group
00681             if (tmp.has_group(group))
00682               throw error(linecount, DUPLICATE_GROUP, group);
00683             else
00684               tmp.set_group(group, comment, linecount);
00685             comment.clear();
00686           }
00687         else // Item
00688           {
00689             std::string::size_type pos = line.find_first_of('=');
00690             if (pos == std::string::npos)
00691               throw error(linecount, INVALID_LINE, line);
00692             if (pos == 0)
00693               throw error(linecount, NO_KEY, line);
00694             key = line.substr(0, pos);
00695             if (pos == line.length() - 1)
00696               value = "";
00697             else
00698               value = line.substr(pos + 1);
00699 
00700             // No group specified
00701             if (group.empty())
00702               throw error(linecount, NO_GROUP, line);
00703 
00704             // Insert item
00705             if (tmp.has_key(group, key))
00706               throw error(linecount, group, DUPLICATE_KEY, key);
00707             else
00708               tmp.set_value(group, key, value, comment, linecount);
00709             comment.clear();
00710           }
00711       }
00712 
00713       kf += tmp;
00714 
00715       return stream;
00716     }
00717 
00725     template <class charT, class traits>
00726     friend
00727     std::basic_ostream<charT,traits>&
00728     operator << (std::basic_ostream<charT,traits>& stream,
00729                  keyfile const&                    kf)
00730     {
00731       unsigned int group_count = 0;
00732 
00733       for (group_map_type::const_iterator gp = kf.groups.begin();
00734            gp != kf.groups.end();
00735            ++gp, ++group_count)
00736         {
00737           if (group_count > 0)
00738             stream << '\n';
00739 
00740           group_type const& group = gp->second;
00741           std::string const& groupname = std::tr1::get<0>(group);
00742           std::string const& comment = std::tr1::get<2>(group);
00743 
00744           if (comment.length() > 0)
00745             print_comment(comment, stream);
00746 
00747           stream << '[' << groupname << ']' << '\n';
00748 
00749           item_map_type const& items(std::tr1::get<1>(group));
00750           for (item_map_type::const_iterator it = items.begin();
00751                it != items.end();
00752                ++it)
00753             {
00754               item_type const& item = it->second;
00755               std::string const& key(std::tr1::get<0>(item));
00756               std::string const& value(std::tr1::get<1>(item));
00757               std::string const& comment(std::tr1::get<2>(item));
00758 
00759               if (comment.length() > 0)
00760                 print_comment(comment, stream);
00761 
00762               stream << key << '=' << value << '\n';
00763             }
00764         }
00765 
00766       return stream;
00767     }
00768 
00769   private:
00776     const group_type *
00777     find_group (std::string const& group) const;
00778 
00785     group_type *
00786     find_group (std::string const& group);
00787 
00795     const item_type *
00796     find_item (std::string const& group,
00797                std::string const& key) const;
00798 
00806     item_type *
00807     find_item (std::string const& group,
00808                std::string const& key);
00809 
00818     void
00819     check_priority (std::string const& group,
00820                     std::string const& key,
00821                     priority           priority,
00822                     bool               valid) const;
00823 
00835     static void
00836     print_comment (std::string const& comment,
00837                    std::ostream&      stream);
00838 
00840     group_map_type groups;
00842     char           separator;
00843 
00844   public:
00857     template<class C, typename T>
00858     static void
00859     set_object_value (C const&            object,
00860                       T             (C::* method)() const,
00861                       keyfile&            keyfile,
00862                       std::string const&  group,
00863                       std::string const&  key)
00864     {
00865       try
00866         {
00867           keyfile.set_value(group, key, (object.*method)());
00868         }
00869       catch (std::runtime_error const& e)
00870         {
00871           throw error(group, key, PASSTHROUGH_GK, e);
00872         }
00873     }
00874 
00887     template<class C, typename T>
00888     static void
00889     set_object_value (C const&            object,
00890                       T const&      (C::* method)() const,
00891                       keyfile&            keyfile,
00892                       std::string const&  group,
00893                       std::string const&  key)
00894     {
00895       try
00896         {
00897           keyfile.set_value(group, key, (object.*method)());
00898         }
00899       catch (std::runtime_error const& e)
00900         {
00901           throw error(group, key, PASSTHROUGH_GK, e);
00902         }
00903     }
00904 
00918     template<class C, typename T>
00919     static void
00920     set_object_list_value (C const&            object,
00921                            T             (C::* method)() const,
00922                            keyfile&            keyfile,
00923                            std::string const&  group,
00924                            std::string const&  key)
00925     {
00926       try
00927         {
00928           keyfile.set_list_value(group, key,
00929                                  (object.*method)().begin(),
00930                                  (object.*method)().end());
00931         }
00932       catch (std::runtime_error const& e)
00933         {
00934           throw error(group, key, PASSTHROUGH_GK, e);
00935         }
00936     }
00937 
00952     template<class C, typename T>
00953     static void
00954     set_object_list_value (C const&            object,
00955                            T const&      (C::* method)() const,
00956                            keyfile&            keyfile,
00957                            std::string const&  group,
00958                            std::string const&  key)
00959     {
00960       try
00961         {
00962           keyfile.set_list_value(group, key,
00963                                  (object.*method)().begin(),
00964                                  (object.*method)().end());
00965         }
00966       catch (std::runtime_error const& e)
00967         {
00968           throw error(group, key, PASSTHROUGH_GK, e);
00969         }
00970     }
00971 
00986     template<class C, typename T>
00987     static void
00988     get_object_value (C&                  object,
00989                       void          (C::* method)(T param),
00990                       keyfile const&      keyfile,
00991                       std::string const&  group,
00992                       std::string const&  key,
00993                       keyfile::priority   priority)
00994     {
00995       try
00996         {
00997           T value;
00998           if (keyfile.get_value(group, key, priority, value))
00999             (object.*method)(value);
01000         }
01001       catch (std::runtime_error const& e)
01002         {
01003           unsigned int line = keyfile.get_line(group, key);
01004           if (line)
01005             throw error(line, group, key, PASSTHROUGH_LGK, e);
01006           else
01007             throw error(group, key, PASSTHROUGH_GK, e);
01008         }
01009     }
01010 
01025     template<class C, typename T>
01026     static void
01027     get_object_value (C&                  object,
01028                       void          (C::* method)(T const& param),
01029                       keyfile const&      keyfile,
01030                       std::string const&  group,
01031                       std::string const&  key,
01032                       keyfile::priority   priority)
01033     {
01034       try
01035         {
01036           T value;
01037           if (keyfile.get_value(group, key, priority, value))
01038             (object.*method)(value);
01039         }
01040       catch (std::runtime_error const& e)
01041         {
01042           unsigned int line = keyfile.get_line(group, key);
01043           if (line)
01044             throw error(line, group, key, PASSTHROUGH_LGK, e);
01045           else
01046             throw error(group, key, PASSTHROUGH_GK, e);
01047         }
01048     }
01049 
01064     template<class C, typename T>
01065     static void
01066     get_object_list_value (C&                  object,
01067                            void          (C::* method)(T param),
01068                            keyfile const&      keyfile,
01069                            std::string const&  group,
01070                            std::string const&  key,
01071                            keyfile::priority   priority)
01072     {
01073       try
01074         {
01075           T value;
01076           if (keyfile.get_list_value(group, key, priority, value))
01077             (object.*method)(value);
01078         }
01079       catch (std::runtime_error const& e)
01080         {
01081           unsigned int line = keyfile.get_line(group, key);
01082           if (line)
01083             throw error(line, group, key, PASSTHROUGH_LGK, e);
01084           else
01085             throw error(group, key, PASSTHROUGH_GK, e);
01086           throw error(keyfile.get_line(group, key),
01087                       group, key, e);
01088         }
01089     }
01090 
01106     template<class C, typename T>
01107     static void
01108     get_object_list_value (C&                  object,
01109                            void          (C::* method)(T const& param),
01110                            keyfile const&      keyfile,
01111                            std::string const&  group,
01112                            std::string const&  key,
01113                            keyfile::priority   priority)
01114     {
01115       try
01116         {
01117           T value;
01118           if (keyfile.get_list_value(group, key, priority, value))
01119             (object.*method)(value);
01120         }
01121       catch (std::runtime_error const& e)
01122         {
01123           unsigned int line = keyfile.get_line(group, key);
01124           if (line)
01125             throw error(line, group, key, PASSTHROUGH_LGK, e);
01126           else
01127             throw error(group, key, PASSTHROUGH_GK, e);
01128           throw error(keyfile.get_line(group, key),
01129                       group, key, e);
01130         }
01131     }
01132   };
01133 
01134 }
01135 
01136 #endif /* SBUILD_KEYFILE_H */
01137 
01138 /*
01139  * Local Variables:
01140  * mode:C++
01141  * End:
01142  */

Generated on Mon Sep 11 23:12:44 2006 for schroot by  doxygen 1.4.7