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> item_type;
00052 
00054     typedef std::map<std::string,item_type> item_map_type;
00055 
00057     typedef std::tr1::tuple<std::string,item_map_type,std::string> group_type;
00058 
00060     typedef std::map<std::string,group_type> group_map_type;
00061 
00062   public:
00064     enum priority
00065       {
00066         PRIORITY_OPTIONAL,   
00067         PRIORITY_REQUIRED,   
00068         PRIORITY_DISALLOWED, 
00069         PRIORITY_DEPRECATED, 
00070         PRIORITY_OBSOLETE    
00071       };
00072 
00074     typedef parse_error error;
00075 
00077     keyfile ();
00078 
00084     keyfile (std::string const& file);
00085 
00091     keyfile (std::istream& stream);
00092 
00094     virtual ~keyfile ();
00095 
00102     string_list
00103     get_groups () const;
00104 
00112     string_list
00113     get_keys (std::string const& group) const;
00114 
00121     bool
00122     has_group (std::string const& group) const;
00123 
00131     bool
00132     has_key (std::string const& group,
00133              std::string const& key) const;
00134 
00142     void
00143     set_group (std::string const& group,
00144                std::string const& comment);
00145 
00152     std::string
00153     get_comment (std::string const& group) const;
00154 
00162     std::string
00163     get_comment (std::string const& group,
00164                  std::string const& key) const;
00165 
00176     template <typename T>
00177     bool
00178     get_value (std::string const& group,
00179                std::string const& key,
00180                T&                 value) const
00181     {
00182       log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00183                             << ", key=" << key << std::endl;
00184       const item_type *found_item = find_item(group, key);
00185       if (found_item)
00186         {
00187           std::string const& strval(std::tr1::get<1>(*found_item));
00188           try
00189             {
00190               value = static_cast<T const&>(parse_value(strval));
00191               return true;
00192             }
00193           catch (parse_value::error const& e)
00194             {
00195               error ep(group, key, parse_error::NONE, e.what());
00196               log_warning() << ep.what() << std::endl;
00197               return false;
00198             }
00199         }
00200       log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00201       return false;
00202     }
00203 
00216     template <typename T>
00217     bool
00218     get_value (std::string const& group,
00219                std::string const& key,
00220                priority           priority,
00221                T&                 value) const
00222     {
00223       bool status = get_value(group, key, value);
00224       check_priority(group, key, priority, status);
00225       return status;
00226     }
00227 
00237     bool
00238     get_locale_string (std::string const& group,
00239                        std::string const& key,
00240                        std::string&       value) const;
00241 
00253     bool
00254     get_locale_string (std::string const& group,
00255                        std::string const& key,
00256                        priority           priority,
00257                        std::string&       value) const;
00258 
00269     bool
00270     get_locale_string (std::string const& group,
00271                        std::string const& key,
00272                        std::string const& locale,
00273                        std::string&       value) const;
00274 
00288     bool
00289     get_locale_string (std::string const& group,
00290                        std::string const& key,
00291                        std::string const& locale,
00292                        priority           priority,
00293                        std::string&       value) const;
00294 
00307     template <typename C>
00308     bool
00309     get_list_value (std::string const& group,
00310                     std::string const& key,
00311                     C&                 container) const
00312     {
00313       std::string item_value;
00314       if (get_value(group, key, item_value))
00315         {
00316           string_list items = split_string(item_value,
00317                                            std::string(1, this->separator));
00318           for (string_list::const_iterator pos = items.begin();
00319                pos != items.end();
00320                ++pos
00321                )
00322             {
00323               container.push_back(static_cast<typename C::const_reference>(parse_value(*pos)));
00324             }
00325           return true;
00326         }
00327       return false;
00328     }
00329 
00344     template <typename C>
00345     bool
00346     get_list_value (std::string const& group,
00347                     std::string const& key,
00348                     priority           priority,
00349                     C&                 container) const
00350     {
00351       bool status = get_list_value(group, key, container);
00352       check_priority(group, key, priority, status);
00353       return status;
00354     }
00355 
00364     template <typename T>
00365     void
00366     set_value (std::string const& group,
00367                std::string const& key,
00368                T const&           value)
00369     {
00370       set_value(group, key, value, std::string());
00371     }
00372 
00382     template <typename T>
00383     void
00384     set_value (std::string const& group,
00385                std::string const& key,
00386                T const&           value,
00387                std::string const& comment)
00388     {
00389       std::ostringstream os;
00390       os.imbue(std::locale("C"));
00391       os << std::boolalpha << value;
00392 
00393       set_group(group, "");
00394       group_type *found_group = find_group(group);
00395       assert (found_group != 0); // should not fail
00396 
00397       item_map_type& items = std::tr1::get<1>(*found_group);
00398 
00399       item_map_type::iterator pos = items.find(key);
00400       if (pos != items.end())
00401         items.erase(pos);
00402 
00403       items.insert
00404         (item_map_type::value_type(key,
00405                                    item_type(key, os.str(), comment)));
00406     }
00407 
00417     template <typename I>
00418     void
00419     set_list_value (std::string const& group,
00420                     std::string const& key,
00421                     I                  begin,
00422                     I                  end)
00423     {
00424       set_list_value(group, key, begin, end, std::string());
00425     }
00426 
00437     template <typename I>
00438     void
00439     set_list_value (std::string const& group,
00440                     std::string const& key,
00441                     I                  begin,
00442                     I                  end,
00443                     std::string const& comment)
00444     {
00445       std::string strval;
00446 
00447       for (I pos = begin; pos != end; ++ pos)
00448         {
00449           std::ostringstream os;
00450           os.imbue(std::locale("C"));
00451           os << std::boolalpha << *pos;
00452           if (os)
00453             {
00454               strval += os.str();
00455               if (pos + 1 != end)
00456                 strval += this->separator;
00457             }
00458         }
00459 
00460       set_value (group, key, strval, comment);
00461     }
00462 
00468     void
00469     remove_group (std::string const& group);
00470 
00477     void
00478     remove_key (std::string const& group,
00479                 std::string const& key);
00480 
00487     keyfile&
00488     operator += (keyfile const& rhs);
00489 
00497     friend keyfile
00498     operator + (keyfile const& lhs,
00499                 keyfile const& rhs);
00500 
00504     template <class charT, class traits>
00505     friend
00506     std::basic_istream<charT,traits>&
00507     operator >> (std::basic_istream<charT,traits>& stream,
00508                  keyfile&                          kf)
00509     {
00510       keyfile tmp;
00511       size_t linecount = 0;
00512       std::string line;
00513       std::string group;
00514       std::string comment;
00515       std::string key;
00516       std::string value;
00517 
00518       while (std::getline(stream, line))
00519       {
00520         linecount++;
00521 
00522         if (line.length() == 0)
00523           {
00524             // Empty line; do nothing.
00525           }
00526         else if (line[0] == '#') // Comment line
00527           {
00528             if (!comment.empty())
00529               comment += '\n';
00530             comment += line.substr(1);
00531           }
00532         else if (line[0] == '[') // Group
00533           {
00534             std::string::size_type fpos = line.find_first_of(']');
00535             std::string::size_type lpos = line.find_last_of(']');
00536             if (fpos == std::string::npos || lpos == std::string::npos ||
00537                 fpos != lpos)
00538               {
00539                 throw error(linecount, parse_error::INVALID_GROUP, line);
00540               }
00541             group = line.substr(1, fpos - 1);
00542 
00543             if (group.length() == 0)
00544               {
00545                 throw error(linecount, parse_error::INVALID_GROUP, line);
00546               }
00547 
00548             // Insert group
00549             if (tmp.has_group(group))
00550               {
00551                 error e(linecount, parse_error::DUPLICATE_GROUP, group);
00552                 log_warning() << e.what() << std::endl;
00553               }
00554             else
00555               tmp.set_group(group, comment);
00556             comment.clear();
00557           }
00558         else // Item
00559           {
00560             std::string::size_type pos = line.find_first_of('=');
00561             if (pos == std::string::npos)
00562               {
00563                 throw error(linecount, parse_error::INVALID_LINE, line);
00564               }
00565             if (pos == 0)
00566               {
00567                 throw error(linecount, parse_error::NO_KEY, line);
00568               }
00569             key = line.substr(0, pos);
00570             if (pos == line.length() - 1)
00571               value = "";
00572             else
00573               value = line.substr(pos + 1);
00574 
00575             // No group specified
00576             if (group.empty())
00577               {
00578                 throw error(linecount, parse_error::NO_GROUP, line);
00579               }
00580 
00581             // Insert item
00582             if (tmp.has_key(group, key))
00583               {
00584                 error e(linecount, group, parse_error::DUPLICATE_KEY, key);
00585                 log_warning() << e.what() << std::endl;
00586               }
00587             else
00588               tmp.set_value(group, key, value, comment);
00589             comment.clear();
00590           }
00591       }
00592 
00593       kf += tmp;
00594 
00595       return stream;
00596     }
00597 
00601     template <class charT, class traits>
00602     friend
00603     std::basic_ostream<charT,traits>&
00604     operator << (std::basic_ostream<charT,traits>& stream,
00605                  keyfile const&                    kf)
00606     {
00607       unsigned int group_count = 0;
00608 
00609       for (group_map_type::const_iterator gp = kf.groups.begin();
00610            gp != kf.groups.end();
00611            ++gp, ++group_count)
00612         {
00613           if (group_count > 0)
00614             stream << '\n';
00615 
00616           group_type const& group = gp->second;
00617           std::string const& groupname = std::tr1::get<0>(group);
00618           std::string const& comment = std::tr1::get<2>(group);
00619 
00620           if (comment.length() > 0)
00621             print_comment(comment, stream);
00622 
00623           stream << '[' << groupname << ']' << '\n';
00624 
00625           item_map_type const& items(std::tr1::get<1>(group));
00626           for (item_map_type::const_iterator it = items.begin();
00627                it != items.end();
00628                ++it)
00629             {
00630               item_type const& item = it->second;
00631               std::string const& key(std::tr1::get<0>(item));
00632               std::string const& value(std::tr1::get<1>(item));
00633               std::string const& comment(std::tr1::get<2>(item));
00634 
00635               if (comment.length() > 0)
00636                 print_comment(comment, stream);
00637 
00638               stream << key << '=' << value << '\n';
00639             }
00640         }
00641 
00642       return stream;
00643     }
00644 
00645   private:
00652     const group_type *
00653     find_group (std::string const& group) const;
00654 
00661     group_type *
00662     find_group (std::string const& group);
00663 
00671     const item_type *
00672     find_item (std::string const& group,
00673                std::string const& key) const;
00674 
00682     item_type *
00683     find_item (std::string const& group,
00684                std::string const& key);
00685 
00694     void
00695     check_priority (std::string const& group,
00696                     std::string const& key,
00697                     priority           priority,
00698                     bool               valid) const;
00699 
00707     static void
00708     print_comment (std::string const& comment,
00709                    std::ostream&      stream);
00710 
00712     group_map_type groups;
00714     char           separator;
00715   };
00716 
00717 }
00718 
00719 #endif /* SBUILD_KEYFILE_H */
00720 
00721 /*
00722  * Local Variables:
00723  * mode:C++
00724  * End:
00725  */

Generated on Mon Jun 26 12:50:25 2006 for schroot by  doxygen 1.4.7