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 
00053   class keyfile
00054   {
00055   private:
00057     typedef std::tr1::tuple<std::string,std::string,std::string> item_type;
00058 
00060     typedef std::map<std::string,item_type> item_map_type;
00061 
00063     typedef std::tr1::tuple<std::string,item_map_type,std::string> group_type;
00064 
00066     typedef std::map<std::string,group_type> group_map_type;
00067 
00068   public:
00070     enum priority
00071       {
00072         PRIORITY_OPTIONAL,   
00073         PRIORITY_REQUIRED,   
00074         PRIORITY_DISALLOWED, 
00075         PRIORITY_DEPRECATED, 
00076         PRIORITY_OBSOLETE    
00077       };
00078 
00080     typedef runtime_error_custom<keyfile> error;
00081 
00083     keyfile();
00084 
00090     keyfile(std::string const& file);
00091 
00097     keyfile(std::istream& stream);
00098 
00100     virtual ~keyfile();
00101 
00108     string_list
00109     get_groups() const;
00110 
00118     string_list
00119     get_keys(std::string const& group) const;
00120 
00127     bool
00128     has_group(std::string const& group) const;
00129 
00137     bool
00138     has_key(std::string const& group,
00139             std::string const& key) const;
00140 
00141 
00142   private:
00151     void
00152     check_priority (std::string const& group,
00153                     std::string const& key,
00154                     priority           priority,
00155                     bool               valid) const;
00156 
00157   public:
00168     template <typename T>
00169     bool
00170     get_value(std::string const& group,
00171               std::string const& key,
00172               T&                 value) const
00173     {
00174       log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00175                             << ", key=" << key << std::endl;
00176       const item_type *found_item = find_item(group, key);
00177       if (found_item)
00178         {
00179           std::string const& strval(std::tr1::get<1>(*found_item));
00180           return parse_value(strval, value);
00181         }
00182       log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00183       return false;
00184     }
00185 
00198     template <typename T>
00199     bool
00200     get_value(std::string const& group,
00201               std::string const& key,
00202               priority           priority,
00203               T&                 value) const
00204     {
00205       bool status = get_value(group, key, value);
00206       check_priority(group, key, priority, status);
00207       return status;
00208     }
00209 
00221     template <typename T, template <typename T> class C>
00222     bool
00223     get_list_value(std::string const& group,
00224                    std::string const& key,
00225                    C<T>&              value) const
00226     {
00227       std::string item_value;
00228       if (get_value(group, key, item_value))
00229         {
00230           C<T> tmplist;
00231           string_list items = split_string(item_value, this->separator);
00232           for (string_list::const_iterator pos = items.begin();
00233                pos != items.end();
00234                ++pos
00235                )
00236             {
00237               T tmpval;
00238               if (parse_value(*pos, tmpval) == false)
00239                 return false;
00240               tmplist.push_back(tmpval);
00241             }
00242           value = tmplist;
00243           return true;
00244         }
00245       return false;
00246     }
00247 
00261     template <typename T, template <typename T> class C>
00262     bool
00263     get_list_value(std::string const& group,
00264                    std::string const& key,
00265                    priority           priority,
00266                    C<T>&              value) const
00267     {
00268       bool status = get_list_value(group, key, value);
00269       check_priority(group, key, priority, status);
00270       return status;
00271     }
00272 
00281     template <typename T>
00282     void
00283     set_value(std::string const& group,
00284               std::string const& key,
00285               T const&           value)
00286     {
00287       std::ostringstream os;
00288       os.imbue(std::locale("C"));
00289       os << std::boolalpha << value;
00290 
00291       if (!has_group(group))
00292         this->groups.insert
00293           (group_map_type::value_type(group,
00294                                       group_type(group,
00295                                                  item_map_type(),
00296                                                  std::string())));
00297       group_type *found_group = find_group(group);
00298       assert (found_group != 0); // should not fail
00299 
00300       item_map_type& items = std::tr1::get<1>(*found_group);
00301 
00302       item_map_type::iterator pos = items.find(key);
00303       if (pos != items.end())
00304         items.erase(pos);
00305 
00306       items.insert
00307         (item_map_type::value_type(key,
00308                                    item_type(key, os.str(), std::string())));
00309 
00310     }
00311 
00321     template <typename T, template <typename T> class C>
00322     void
00323     set_list_value(std::string const& group,
00324                    std::string const& key,
00325                    C<T> const&        value)
00326     {
00327       std::string strval;
00328 
00329       for (typename C<T>::const_iterator pos = value.begin();
00330            pos != value.end();
00331            ++ pos)
00332         {
00333           std::ostringstream os;
00334           os.imbue(std::locale("C"));
00335           os << std::boolalpha << *pos;
00336           if (os)
00337             {
00338               strval += os.str();
00339               if (pos + 1 != value.end())
00340                 strval += this->separator;
00341             }
00342         }
00343 
00344       set_value (group, key, strval);
00345     }
00346 
00352     void
00353     remove_group(std::string const& group);
00354 
00361     void
00362     remove_key(std::string const& group,
00363                std::string const& key);
00364 
00368     template <class charT, class traits>
00369     friend
00370     std::basic_istream<charT,traits>&
00371     operator >> (std::basic_istream<charT,traits>& stream, keyfile& kf)
00372     {
00373       size_t linecount = 0;
00374       std::string line;
00375       std::string group;
00376       std::string group_comment;
00377       std::string comment;
00378       std::string key;
00379       std::string value;
00380 
00381       while (std::getline(stream, line))
00382       {
00383         if (line[0] == '#') // Comment line
00384           {
00385             if (!comment.empty())
00386               comment += '\n';
00387             comment += line.substr(1);
00388           }
00389         else if (line[0] == '[') // Group
00390           {
00391             std::string::size_type fpos = line.find_first_of(']');
00392             std::string::size_type lpos = line.find_last_of(']');
00393             if (fpos == std::string::npos || fpos != lpos)
00394               {
00395                 boost::format fmt(_("Line %1%: invalid group entry: %2%"));
00396                 fmt % linecount % line;
00397                 throw error(fmt);
00398               }
00399             group = line.substr(1, fpos - 1);
00400 
00401             if (!comment.empty())
00402               {
00403                 if (!group_comment.empty())
00404                   group_comment += '\n';
00405                 group_comment += comment;
00406                 comment.clear();
00407               }
00408             // Add group
00409             // Add group comment
00410             // Check if group already inserted, and append comments if needed.
00411           }
00412         else if (line.length() == 0)
00413           {
00414             // Do nothing.
00415           }
00416         else
00417           {
00418             std::string::size_type pos = line.find_first_of('=');
00419             if (pos == std::string::npos)
00420               {
00421                 boost::format fmt(_("Line %1%: invalid line: %2%"));
00422                 fmt % linecount % line;
00423                 throw error(fmt);
00424               }
00425             if (pos == 0)
00426               {
00427                 boost::format fmt(_("Line %1%: no key specified: %2%"));
00428                 fmt % linecount % line;
00429                 throw error(fmt);
00430               }
00431             key = line.substr(0, pos);
00432             if (pos == line.length() - 1)
00433               value = "";
00434             else
00435               value = line.substr(pos + 1);
00436 
00437             // Insert item
00438             kf.set_value(group, key, value);
00439             // Set item comment
00440             // Set group comment?
00441           }
00442 
00443         linecount++;
00444       }
00445 
00446       return stream;
00447     }
00448 
00449   private:
00457     static void
00458     print_comment(std::string const& comment,
00459                   std::ostream&      stream);
00460 
00461   public:
00465     template <class charT, class traits>
00466     friend
00467     std::basic_ostream<charT,traits>&
00468     operator << (std::basic_ostream<charT,traits>& stream, keyfile const& kf)
00469     {
00470       unsigned int group_count = 0;
00471 
00472       for (group_map_type::const_iterator gp = kf.groups.begin();
00473            gp != kf.groups.end();
00474            ++gp, ++group_count)
00475         {
00476           if (group_count > 0)
00477             stream << '\n';
00478 
00479           group_type const& group = gp->second;
00480           std::string const& groupname = std::tr1::get<0>(group);
00481           std::string const& comment = std::tr1::get<2>(group);
00482 
00483           if (comment.length() > 0)
00484             print_comment(comment, stream);
00485 
00486           stream << '[' << groupname << ']' << '\n';
00487 
00488           item_map_type const& items(std::tr1::get<1>(group));
00489           for (item_map_type::const_iterator it = items.begin();
00490                it != items.end();
00491                ++it)
00492             {
00493               item_type const& item = it->second;
00494               std::string const& key(std::tr1::get<0>(item));
00495               std::string const& value(std::tr1::get<1>(item));
00496               std::string const& comment(std::tr1::get<2>(item));
00497 
00498               if (comment.length() > 0)
00499                 print_comment(comment, stream);
00500 
00501               stream << key << '=' << value << '\n';
00502             }
00503         }
00504 
00505       return stream;
00506     }
00507 
00508   private:
00515     const group_type *
00516     find_group(std::string const& group) const;
00517 
00524     group_type *
00525     find_group(std::string const& group);
00526 
00534     const item_type *
00535     find_item(std::string const& group,
00536               std::string const& key) const;
00537 
00545     item_type *
00546     find_item(std::string const& group,
00547               std::string const& key);
00548 
00550     group_map_type groups;
00552     char           separator;
00553   };
00554 
00555 }
00556 
00557 #endif /* SBUILD_KEYFILE_H */
00558 
00559 /*
00560  * Local Variables:
00561  * mode:C++
00562  * End:
00563  */

Generated on Mon Jan 30 13:22:56 2006 for schroot by  doxygen 1.4.6