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 <cassert>
00024 #include <iostream>
00025 #include <map>
00026 #include <string>
00027 #include <sstream>
00028 #include <tr1/tuple>
00029 
00030 #include <boost/format.hpp>
00031 
00032 #include "sbuild-error.h"
00033 #include "sbuild-i18n.h"
00034 #include "sbuild-log.h"
00035 #include "sbuild-parse-value.h"
00036 #include "sbuild-types.h"
00037 #include "sbuild-util.h"
00038 
00039 namespace sbuild
00040 {
00041 
00048   class keyfile
00049   {
00050   private:
00052     typedef std::tr1::tuple<std::string,std::string,std::string> 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> 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     typedef runtime_error_custom<keyfile> error;
00076 
00078     keyfile ();
00079 
00085     keyfile (std::string const& file);
00086 
00092     keyfile (std::istream& stream);
00093 
00095     virtual ~keyfile ();
00096 
00103     string_list
00104     get_groups () const;
00105 
00113     string_list
00114     get_keys (std::string const& group) const;
00115 
00122     bool
00123     has_group (std::string const& group) const;
00124 
00132     bool
00133     has_key (std::string const& group,
00134              std::string const& key) const;
00135 
00143     void
00144     set_group (std::string const& group,
00145                std::string const& comment);
00146 
00153     std::string
00154     get_comment (std::string const& group) const;
00155 
00163     std::string
00164     get_comment (std::string const& group,
00165                  std::string const& key) const;
00166 
00177     template <typename T>
00178     bool
00179     get_value (std::string const& group,
00180                std::string const& key,
00181                T&                 value) const
00182     {
00183       log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00184                             << ", key=" << key << std::endl;
00185       const item_type *found_item = find_item(group, key);
00186       if (found_item)
00187         {
00188           std::string const& strval(std::tr1::get<1>(*found_item));
00189           return parse_value(strval, value);
00190         }
00191       log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00192       return false;
00193     }
00194 
00207     template <typename T>
00208     bool
00209     get_value (std::string const& group,
00210                std::string const& key,
00211                priority           priority,
00212                T&                 value) const
00213     {
00214       bool status = get_value(group, key, value);
00215       check_priority(group, key, priority, status);
00216       return status;
00217     }
00218 
00228     bool
00229     get_locale_string (std::string const& group,
00230                        std::string const& key,
00231                        std::string&       value) const;
00232 
00244     bool
00245     get_locale_string (std::string const& group,
00246                        std::string const& key,
00247                        priority           priority,
00248                        std::string&       value) const;
00249 
00260     bool
00261     get_locale_string (std::string const& group,
00262                        std::string const& key,
00263                        std::string const& locale,
00264                        std::string&       value) const;
00265 
00279     bool
00280     get_locale_string (std::string const& group,
00281                        std::string const& key,
00282                        std::string const& locale,
00283                        priority           priority,
00284                        std::string&       value) const;
00285 
00297     template <typename T, template <typename T> class C>
00298     bool
00299     get_list_value (std::string const& group,
00300                     std::string const& key,
00301                     C<T>&              value) const
00302     {
00303       std::string item_value;
00304       if (get_value(group, key, item_value))
00305         {
00306           C<T> tmplist;
00307           string_list items = split_string(item_value, this->separator);
00308           for (string_list::const_iterator pos = items.begin();
00309                pos != items.end();
00310                ++pos
00311                )
00312             {
00313               T tmpval;
00314               if (parse_value(*pos, tmpval) == false)
00315                 return false;
00316               tmplist.push_back(tmpval);
00317             }
00318           value = tmplist;
00319           return true;
00320         }
00321       return false;
00322     }
00323 
00337     template <typename T, template <typename T> class C>
00338     bool
00339     get_list_value (std::string const& group,
00340                     std::string const& key,
00341                     priority           priority,
00342                     C<T>&              value) const
00343     {
00344       bool status = get_list_value(group, key, value);
00345       check_priority(group, key, priority, status);
00346       return status;
00347     }
00348 
00357     template <typename T>
00358     void
00359     set_value (std::string const& group,
00360                std::string const& key,
00361                T const&           value)
00362     {
00363       set_value(group, key, value, std::string());
00364     }
00365 
00375     template <typename T>
00376     void
00377     set_value (std::string const& group,
00378                std::string const& key,
00379                T const&           value,
00380                std::string const& comment)
00381     {
00382       std::ostringstream os;
00383       os.imbue(std::locale("C"));
00384       os << std::boolalpha << value;
00385 
00386       set_group(group, "");
00387       group_type *found_group = find_group(group);
00388       assert (found_group != 0); // should not fail
00389 
00390       item_map_type& items = std::tr1::get<1>(*found_group);
00391 
00392       item_map_type::iterator pos = items.find(key);
00393       if (pos != items.end())
00394         items.erase(pos);
00395 
00396       items.insert
00397         (item_map_type::value_type(key,
00398                                    item_type(key, os.str(), comment)));
00399     }
00400 
00410     template <typename T, template <typename T> class C>
00411     void
00412     set_list_value (std::string const& group,
00413                     std::string const& key,
00414                     C<T> const&        value)
00415     {
00416       set_list_value(group, key, value, std::string());
00417     }
00418 
00429     template <typename T, template <typename T> class C>
00430     void
00431     set_list_value (std::string const& group,
00432                     std::string const& key,
00433                     C<T> const&        value,
00434                     std::string const& comment)
00435     {
00436       std::string strval;
00437 
00438       for (typename C<T>::const_iterator pos = value.begin();
00439            pos != value.end();
00440            ++ pos)
00441         {
00442           std::ostringstream os;
00443           os.imbue(std::locale("C"));
00444           os << std::boolalpha << *pos;
00445           if (os)
00446             {
00447               strval += os.str();
00448               if (pos + 1 != value.end())
00449                 strval += this->separator;
00450             }
00451         }
00452 
00453       set_value (group, key, strval, comment);
00454     }
00455 
00461     void
00462     remove_group (std::string const& group);
00463 
00470     void
00471     remove_key (std::string const& group,
00472                 std::string const& key);
00473 
00480     keyfile&
00481     operator += (keyfile const& rhs);
00482 
00490     friend keyfile
00491     operator + (keyfile const& lhs,
00492                 keyfile const& rhs);
00493 
00497     template <class charT, class traits>
00498     friend
00499     std::basic_istream<charT,traits>&
00500     operator >> (std::basic_istream<charT,traits>& stream,
00501                  keyfile&                          kf)
00502     {
00503       keyfile tmp;
00504       size_t linecount = 0;
00505       std::string line;
00506       std::string group;
00507       std::string comment;
00508       std::string key;
00509       std::string value;
00510 
00511       while (std::getline(stream, line))
00512       {
00513         linecount++;
00514 
00515         if (line[0] == '#') // Comment line
00516           {
00517             if (!comment.empty())
00518               comment += '\n';
00519             comment += line.substr(1);
00520           }
00521         else if (line[0] == '[') // Group
00522           {
00523             std::string::size_type fpos = line.find_first_of(']');
00524             std::string::size_type lpos = line.find_last_of(']');
00525             if (fpos == std::string::npos || fpos != lpos)
00526               {
00527                 boost::format fmt(_("line %1%: invalid group entry: %2%"));
00528                 fmt % linecount % line;
00529                 throw error(fmt);
00530               }
00531             group = line.substr(1, fpos - 1);
00532 
00533             // Insert group
00534             if (tmp.has_group(group))
00535               {
00536                 log_warning()
00537                   << boost::format(_("line %1%: duplicate group entry: %2%"))
00538                   % linecount % group
00539                   << std::endl;
00540               }
00541             else
00542               tmp.set_group(group, comment);
00543             comment.clear();
00544           }
00545         else if (line.length() == 0)
00546           {
00547             // Empty line; do nothing.
00548           }
00549         else // Item
00550           {
00551             std::string::size_type pos = line.find_first_of('=');
00552             if (pos == std::string::npos)
00553               {
00554                 boost::format fmt(_("line %1%: invalid line: %2%"));
00555                 fmt % linecount % line;
00556                 throw error(fmt);
00557               }
00558             if (pos == 0)
00559               {
00560                 boost::format fmt(_("line %1%: no key specified: %2%"));
00561                 fmt % linecount % line;
00562                 throw error(fmt);
00563               }
00564             key = line.substr(0, pos);
00565             if (pos == line.length() - 1)
00566               value = "";
00567             else
00568               value = line.substr(pos + 1);
00569 
00570             // Insert item
00571             if (tmp.has_key(group, key))
00572               {
00573                 log_warning()
00574                   << boost::format(_("line %1%: group %2%: duplicate key entry: %3%"))
00575                   % linecount % group % key
00576                   << std::endl;
00577               }
00578             else
00579               tmp.set_value(group, key, value, comment);
00580             comment.clear();
00581           }
00582       }
00583 
00584       kf += tmp;
00585 
00586       return stream;
00587     }
00588 
00592     template <class charT, class traits>
00593     friend
00594     std::basic_ostream<charT,traits>&
00595     operator << (std::basic_ostream<charT,traits>& stream,
00596                  keyfile const&                    kf)
00597     {
00598       unsigned int group_count = 0;
00599 
00600       for (group_map_type::const_iterator gp = kf.groups.begin();
00601            gp != kf.groups.end();
00602            ++gp, ++group_count)
00603         {
00604           if (group_count > 0)
00605             stream << '\n';
00606 
00607           group_type const& group = gp->second;
00608           std::string const& groupname = std::tr1::get<0>(group);
00609           std::string const& comment = std::tr1::get<2>(group);
00610 
00611           if (comment.length() > 0)
00612             print_comment(comment, stream);
00613 
00614           stream << '[' << groupname << ']' << '\n';
00615 
00616           item_map_type const& items(std::tr1::get<1>(group));
00617           for (item_map_type::const_iterator it = items.begin();
00618                it != items.end();
00619                ++it)
00620             {
00621               item_type const& item = it->second;
00622               std::string const& key(std::tr1::get<0>(item));
00623               std::string const& value(std::tr1::get<1>(item));
00624               std::string const& comment(std::tr1::get<2>(item));
00625 
00626               if (comment.length() > 0)
00627                 print_comment(comment, stream);
00628 
00629               stream << key << '=' << value << '\n';
00630             }
00631         }
00632 
00633       return stream;
00634     }
00635 
00636   private:
00643     const group_type *
00644     find_group (std::string const& group) const;
00645 
00652     group_type *
00653     find_group (std::string const& group);
00654 
00662     const item_type *
00663     find_item (std::string const& group,
00664                std::string const& key) const;
00665 
00673     item_type *
00674     find_item (std::string const& group,
00675                std::string const& key);
00676 
00685     void
00686     check_priority (std::string const& group,
00687                     std::string const& key,
00688                     priority           priority,
00689                     bool               valid) const;
00690 
00698     static void
00699     print_comment (std::string const& comment,
00700                    std::ostream&      stream);
00701 
00703     group_map_type groups;
00705     char           separator;
00706   };
00707 
00708 }
00709 
00710 #endif /* SBUILD_KEYFILE_H */
00711 
00712 /*
00713  * Local Variables:
00714  * mode:C++
00715  * End:
00716  */

Generated on Sun Mar 19 12:07:48 2006 for schroot by  doxygen 1.4.6