00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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);
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] == '#')
00304 {
00305 if (!comment.empty())
00306 comment += '\n';
00307 comment += line.substr(1);
00308 }
00309 else if (line[0] == '[')
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
00329
00330
00331 }
00332 else if (line.length() == 0)
00333 {
00334
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
00358 kf.set_value(group, key, value);
00359
00360
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
00478
00479
00480
00481
00482
00483