sbuild-keyfile.h

00001 /* Copyright © 2005  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-types.h"
00035 #include "sbuild-util.h"
00036 
00037 namespace sbuild
00038 {
00039 
00049   class keyfile
00050   {
00051   private:
00053     typedef std::tr1::tuple<std::string,std::string,std::string> item_type;
00054 
00056     typedef std::map<std::string,item_type> item_map_type;
00057 
00059     typedef std::tr1::tuple<std::string,item_map_type,std::string> group_type;
00060 
00062     typedef std::map<std::string,group_type> group_map_type;
00063 
00064   public:
00066     typedef runtime_error_custom<keyfile> error;
00067 
00073     keyfile(const std::string& file);
00074 
00080     keyfile(std::istream& stream);
00081 
00083     virtual ~keyfile();
00084 
00091     string_list
00092     get_groups() const;
00093 
00101     string_list
00102     get_keys(const std::string& group) const;
00103 
00110     bool
00111     has_group(const std::string& group) const;
00112 
00120     bool
00121     has_key(const std::string& group,
00122             const std::string& key) const;
00123 
00134     template <typename T>
00135     bool
00136     get_value(const std::string& group,
00137               const std::string& key,
00138               T& value) const
00139     {
00140       const item_type *found_item = find_item(group, key);
00141       if (found_item)
00142         {
00143           const std::string& strval(std::tr1::get<1>(*found_item));
00144           std::istringstream is(strval);
00145           T tmpval;
00146           is >> tmpval;
00147           if (!is.bad())
00148             {
00149               value = tmpval;
00150               return true;
00151             }
00152         }
00153       return false;
00154     }
00155 
00167     template <typename T, template <typename T> class C>
00168     bool
00169     get_list_value(const std::string& group,
00170                    const std::string& key,
00171                    C<T>& value) const
00172     {
00173       std::string item_value;
00174       if (get_value(group, key, item_value))
00175         {
00176           C<T> tmplist;
00177           string_list items = split_string(item_value, this->separator);
00178           for (string_list::const_iterator pos = items.begin();
00179                pos != items.end();
00180                ++pos
00181                )
00182             {
00183               std::istringstream is(*pos);
00184               T tmpval;
00185               is >> tmpval;
00186               if (!is)
00187                 return false;
00188               tmplist.push_back(tmpval);
00189             }
00190           value = tmplist;
00191         }
00192       return false;
00193     }
00194 
00203     template <typename T>
00204     void
00205     set_value(const std::string& group,
00206               const std::string& key,
00207               const T& value)
00208     {
00209       std::ostringstream os;
00210       os << value;
00211 
00212       if (!has_group(group))
00213         this->groups.insert
00214           (group_map_type::value_type(group,
00215                                       group_type(group,
00216                                                  item_map_type(),
00217                                                  std::string())));
00218       group_type *found_group = find_group(group);
00219       assert (found_group != 0); // should not fail
00220 
00221       item_map_type& items = std::tr1::get<1>(*found_group);
00222 
00223       item_map_type::iterator pos = items.find(key);
00224       if (pos != items.end())
00225         items.erase(pos);
00226 
00227       items.insert
00228         (item_map_type::value_type(key,
00229                                    item_type(key, value, std::string())));
00230 
00231     }
00232 
00242     template <typename T, template <typename T> class C>
00243     void
00244     set_list_value(const std::string& group,
00245                    const std::string& key,
00246                    const C<T>& value)
00247     {
00248       std::string strval;
00249 
00250       for (typename C<T>::const_iterator pos = value.begin();
00251            pos != value.end();
00252            ++ pos)
00253         {
00254           std::ostringstream os;
00255           os << *pos;
00256           if (os)
00257             {
00258               strval += os.str();
00259               if (pos += 1 != value.end())
00260                 strval += this->separator;
00261             }
00262         }
00263 
00264       set_value (group, key, strval);
00265     }
00266 
00272     void
00273     remove_group(const std::string& group);
00274 
00281     void
00282     remove_key(const std::string& group,
00283                const std::string& key);
00284 
00288     template <class charT, class traits>
00289     friend
00290     std::basic_istream<charT,traits>&
00291     operator >> (std::basic_istream<charT,traits>& stream, keyfile& kf)
00292     {
00293       size_t linecount = 0;
00294       std::string line;
00295       std::string group;
00296       std::string group_comment;
00297       std::string comment;
00298       std::string key;
00299       std::string value;
00300 
00301       while (std::getline(stream, line))
00302       {
00303         if (line[0] == '#') // Comment line
00304           {
00305             if (!comment.empty())
00306               comment += '\n';
00307             comment += line.substr(1);
00308           }
00309         else if (line[0] == '[') // Group
00310           {
00311             std::string::size_type fpos = line.find_first_of(']');
00312             std::string::size_type lpos = line.find_last_of(']');
00313             if (fpos == std::string::npos || fpos != lpos)
00314               {
00315                 boost::format fmt(_("Line %1%: invalid group entry: %2%"));
00316                 fmt % linecount % line;
00317                 throw error(fmt);
00318               }
00319             group = line.substr(1, fpos - 2);
00320 
00321             if (!comment.empty())
00322               {
00323                 if (!group_comment.empty())
00324                   group_comment += '\n';
00325                 group_comment += comment;
00326                 comment.clear();
00327               }
00328             // Add group
00329             // Add group comment
00330             // Check if group already inserted, and append comments if needed.
00331           }
00332         else if (line.length() == 0)
00333           {
00334             // Do nothing.
00335           }
00336         else
00337           {
00338             std::string::size_type pos = line.find_first_of('=');
00339             if (pos == std::string::npos)
00340               {
00341                 boost::format fmt(_("Line %1%: invalid line: %2%"));
00342                 fmt % linecount % line;
00343                 throw error(fmt);
00344               }
00345             if (pos == 0)
00346               {
00347                 boost::format fmt(_("Line %1%: no key specified: %2%"));
00348                 fmt % linecount % line;
00349                 throw error(fmt);
00350               }
00351             key = line.substr(0, pos - 1);
00352             if (pos == line.length() - 1)
00353               value = "";
00354             else
00355               value = line.substr(pos + 1);
00356 
00357             // Insert item
00358             kf.set_value(group, key, value);
00359             // Set item comment
00360             // Set group comment?
00361           }
00362 
00363         linecount++;
00364       }
00365 
00366       return stream;
00367     }
00368 
00369   private:
00377     void
00378     print_comment(const std::string& comment,
00379                   std::ostream&      stream) const;
00380 
00381   public:
00385     template <class charT, class traits>
00386     friend
00387     std::basic_ostream<charT,traits>&
00388     operator << (std::basic_ostream<charT,traits>& stream, const keyfile& kf)
00389     {
00390       unsigned int group_count = 0;
00391 
00392       for (group_map_type::const_iterator gp = kf.groups.begin();
00393            gp != kf.groups.end();
00394            ++gp, ++group_count)
00395         {
00396           if (group_count > 0)
00397             stream << '\n';
00398 
00399           const group_type& group = gp->second;
00400           const std::string& groupname = std::tr1::get<0>(group);
00401           const std::string& comment = std::tr1::get<2>(group);
00402 
00403           if (comment.length() > 0)
00404             print_comment(comment, stream);
00405 
00406           stream << '[' << groupname << ']' << '\n';
00407 
00408           const item_map_type& items(std::tr1::get<1>(group));
00409           for (item_map_type::const_iterator it = items.begin();
00410                it != items.end();
00411                ++it)
00412             {
00413               const item_type& item = it->second;
00414               const std::string& key(std::tr1::get<0>(item));
00415               const std::string& value(std::tr1::get<1>(item));
00416               const std::string& comment(std::tr1::get<2>(item));
00417 
00418               if (comment.length() > 0)
00419                 print_comment(comment, stream);
00420 
00421               stream << key << '=' << value;
00422             }
00423         }
00424 
00425       return stream;
00426     }
00427 
00428   private:
00435     const group_type *
00436     find_group(const std::string& group) const;
00437 
00444     group_type *
00445     find_group(const std::string& group);
00446 
00454     const item_type *
00455     find_item(const std::string& group,
00456               const std::string& key) const;
00457 
00465     item_type *
00466     find_item(const std::string& group,
00467               const std::string& key);
00468 
00470     group_map_type groups;
00472     char           separator;
00473   };
00474 
00475 }
00476 
00477 #endif /* SBUILD_KEYFILE_H */
00478 
00479 /*
00480  * Local Variables:
00481  * mode:C++
00482  * End:
00483  */

Generated on Thu Dec 29 17:20:02 2005 for schroot by  doxygen 1.4.5