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-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);
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] == '#')
00516 {
00517 if (!comment.empty())
00518 comment += '\n';
00519 comment += line.substr(1);
00520 }
00521 else if (line[0] == '[')
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
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
00548 }
00549 else
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
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
00711
00712
00713
00714
00715
00716