- Main Page
- Namespaces
- Classes
- Files
- Directories
- Related Pages

- File List
- File Members

# 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  */