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 "sbuild-config.h"
00024
00025 #include <cassert>
00026 #include <iostream>
00027 #include <map>
00028 #include <string>
00029 #include <sstream>
00030
00031 #ifdef HAVE_TR1_TUPLE
00032 #include <tr1/tuple>
00033 #elif HAVE_BOOST_TUPLE_TUPLE_HPP
00034 #include <boost/tuple/tuple.hpp>
00035 namespace std { namespace tr1 { using boost::tuple; using boost::get; } }
00036 #else
00037 #error A shared_ptr implementation is not available
00038 #endif
00039
00040 #include <boost/format.hpp>
00041
00042 #include "sbuild-error.h"
00043 #include "sbuild-i18n.h"
00044 #include "sbuild-log.h"
00045 #include "sbuild-parse-value.h"
00046 #include "sbuild-types.h"
00047 #include "sbuild-util.h"
00048
00049 namespace sbuild
00050 {
00051
00058 class keyfile
00059 {
00060 private:
00062 typedef std::tr1::tuple<std::string,std::string,std::string> item_type;
00063
00065 typedef std::map<std::string,item_type> item_map_type;
00066
00068 typedef std::tr1::tuple<std::string,item_map_type,std::string> group_type;
00069
00071 typedef std::map<std::string,group_type> group_map_type;
00072
00073 public:
00075 enum priority
00076 {
00077 PRIORITY_OPTIONAL,
00078 PRIORITY_REQUIRED,
00079 PRIORITY_DISALLOWED,
00080 PRIORITY_DEPRECATED,
00081 PRIORITY_OBSOLETE
00082 };
00083
00085 typedef runtime_error_custom<keyfile> error;
00086
00088 keyfile ();
00089
00095 keyfile (std::string const& file);
00096
00102 keyfile (std::istream& stream);
00103
00105 virtual ~keyfile ();
00106
00113 string_list
00114 get_groups () const;
00115
00123 string_list
00124 get_keys (std::string const& group) const;
00125
00132 bool
00133 has_group (std::string const& group) const;
00134
00142 bool
00143 has_key (std::string const& group,
00144 std::string const& key) const;
00145
00153 void
00154 set_group (std::string const& group,
00155 std::string const& comment);
00156
00163 std::string
00164 get_comment (std::string const& group) const;
00165
00173 std::string
00174 get_comment (std::string const& group,
00175 std::string const& key) const;
00176
00187 template <typename T>
00188 bool
00189 get_value (std::string const& group,
00190 std::string const& key,
00191 T& value) const
00192 {
00193 log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00194 << ", key=" << key << std::endl;
00195 const item_type *found_item = find_item(group, key);
00196 if (found_item)
00197 {
00198 std::string const& strval(std::tr1::get<1>(*found_item));
00199 try
00200 {
00201 value = static_cast<T const&>(parse_value(strval));
00202 return true;
00203 }
00204 catch (parse_value::error const& e)
00205 {
00206 log_warning() << boost::format("[%1%] %2%: %3%\n")
00207 % group % key % e.what();
00208 return false;
00209 }
00210 }
00211 log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00212 return false;
00213 }
00214
00227 template <typename T>
00228 bool
00229 get_value (std::string const& group,
00230 std::string const& key,
00231 priority priority,
00232 T& value) const
00233 {
00234 bool status = get_value(group, key, value);
00235 check_priority(group, key, priority, status);
00236 return status;
00237 }
00238
00248 bool
00249 get_locale_string (std::string const& group,
00250 std::string const& key,
00251 std::string& value) const;
00252
00264 bool
00265 get_locale_string (std::string const& group,
00266 std::string const& key,
00267 priority priority,
00268 std::string& value) const;
00269
00280 bool
00281 get_locale_string (std::string const& group,
00282 std::string const& key,
00283 std::string const& locale,
00284 std::string& value) const;
00285
00299 bool
00300 get_locale_string (std::string const& group,
00301 std::string const& key,
00302 std::string const& locale,
00303 priority priority,
00304 std::string& value) const;
00305
00318 template <typename C>
00319 bool
00320 get_list_value (std::string const& group,
00321 std::string const& key,
00322 C& container) const
00323 {
00324 std::string item_value;
00325 if (get_value(group, key, item_value))
00326 {
00327 string_list items = split_string(item_value, this->separator);
00328 for (string_list::const_iterator pos = items.begin();
00329 pos != items.end();
00330 ++pos
00331 )
00332 {
00333 container.push_back(static_cast<typename C::const_reference>(parse_value(*pos)));
00334
00335 }
00336 return true;
00337 }
00338 return false;
00339 }
00340
00355 template <typename C>
00356 bool
00357 get_list_value (std::string const& group,
00358 std::string const& key,
00359 priority priority,
00360 C& container) const
00361 {
00362 bool status = get_list_value(group, key, container);
00363 check_priority(group, key, priority, status);
00364 return status;
00365 }
00366
00375 template <typename T>
00376 void
00377 set_value (std::string const& group,
00378 std::string const& key,
00379 T const& value)
00380 {
00381 set_value(group, key, value, std::string());
00382 }
00383
00393 template <typename T>
00394 void
00395 set_value (std::string const& group,
00396 std::string const& key,
00397 T const& value,
00398 std::string const& comment)
00399 {
00400 std::ostringstream os;
00401 os.imbue(std::locale("C"));
00402 os << std::boolalpha << value;
00403
00404 set_group(group, "");
00405 group_type *found_group = find_group(group);
00406 assert (found_group != 0);
00407
00408 item_map_type& items = std::tr1::get<1>(*found_group);
00409
00410 item_map_type::iterator pos = items.find(key);
00411 if (pos != items.end())
00412 items.erase(pos);
00413
00414 items.insert
00415 (item_map_type::value_type(key,
00416 item_type(key, os.str(), comment)));
00417 }
00418
00428 template <typename I>
00429 void
00430 set_list_value (std::string const& group,
00431 std::string const& key,
00432 I begin,
00433 I end)
00434 {
00435 set_list_value(group, key, begin, end, std::string());
00436 }
00437
00448 template <typename I>
00449 void
00450 set_list_value (std::string const& group,
00451 std::string const& key,
00452 I begin,
00453 I end,
00454 std::string const& comment)
00455 {
00456 std::string strval;
00457
00458 for (I pos = begin; pos != end; ++ pos)
00459 {
00460 std::ostringstream os;
00461 os.imbue(std::locale("C"));
00462 os << std::boolalpha << *pos;
00463 if (os)
00464 {
00465 strval += os.str();
00466 if (pos + 1 != end)
00467 strval += this->separator;
00468 }
00469 }
00470
00471 set_value (group, key, strval, comment);
00472 }
00473
00479 void
00480 remove_group (std::string const& group);
00481
00488 void
00489 remove_key (std::string const& group,
00490 std::string const& key);
00491
00498 keyfile&
00499 operator += (keyfile const& rhs);
00500
00508 friend keyfile
00509 operator + (keyfile const& lhs,
00510 keyfile const& rhs);
00511
00515 template <class charT, class traits>
00516 friend
00517 std::basic_istream<charT,traits>&
00518 operator >> (std::basic_istream<charT,traits>& stream,
00519 keyfile& kf)
00520 {
00521 keyfile tmp;
00522 size_t linecount = 0;
00523 std::string line;
00524 std::string group;
00525 std::string comment;
00526 std::string key;
00527 std::string value;
00528
00529 while (std::getline(stream, line))
00530 {
00531 linecount++;
00532
00533 if (line[0] == '#')
00534 {
00535 if (!comment.empty())
00536 comment += '\n';
00537 comment += line.substr(1);
00538 }
00539 else if (line[0] == '[')
00540 {
00541 std::string::size_type fpos = line.find_first_of(']');
00542 std::string::size_type lpos = line.find_last_of(']');
00543 if (fpos == std::string::npos || fpos != lpos)
00544 {
00545 boost::format fmt(_("line %1%: invalid group entry: %2%"));
00546 fmt % linecount % line;
00547 throw error(fmt);
00548 }
00549 group = line.substr(1, fpos - 1);
00550
00551
00552 if (tmp.has_group(group))
00553 {
00554 log_warning()
00555 << boost::format(_("line %1%: duplicate group entry: %2%"))
00556 % linecount % group
00557 << std::endl;
00558 }
00559 else
00560 tmp.set_group(group, comment);
00561 comment.clear();
00562 }
00563 else if (line.length() == 0)
00564 {
00565
00566 }
00567 else
00568 {
00569 std::string::size_type pos = line.find_first_of('=');
00570 if (pos == std::string::npos)
00571 {
00572 boost::format fmt(_("line %1%: invalid line: %2%"));
00573 fmt % linecount % line;
00574 throw error(fmt);
00575 }
00576 if (pos == 0)
00577 {
00578 boost::format fmt(_("line %1%: no key specified: %2%"));
00579 fmt % linecount % line;
00580 throw error(fmt);
00581 }
00582 key = line.substr(0, pos);
00583 if (pos == line.length() - 1)
00584 value = "";
00585 else
00586 value = line.substr(pos + 1);
00587
00588
00589 if (tmp.has_key(group, key))
00590 {
00591 log_warning()
00592 << boost::format(_("line %1%: group %2%: duplicate key entry: %3%"))
00593 % linecount % group % key
00594 << std::endl;
00595 }
00596 else
00597 tmp.set_value(group, key, value, comment);
00598 comment.clear();
00599 }
00600 }
00601
00602 kf += tmp;
00603
00604 return stream;
00605 }
00606
00610 template <class charT, class traits>
00611 friend
00612 std::basic_ostream<charT,traits>&
00613 operator << (std::basic_ostream<charT,traits>& stream,
00614 keyfile const& kf)
00615 {
00616 unsigned int group_count = 0;
00617
00618 for (group_map_type::const_iterator gp = kf.groups.begin();
00619 gp != kf.groups.end();
00620 ++gp, ++group_count)
00621 {
00622 if (group_count > 0)
00623 stream << '\n';
00624
00625 group_type const& group = gp->second;
00626 std::string const& groupname = std::tr1::get<0>(group);
00627 std::string const& comment = std::tr1::get<2>(group);
00628
00629 if (comment.length() > 0)
00630 print_comment(comment, stream);
00631
00632 stream << '[' << groupname << ']' << '\n';
00633
00634 item_map_type const& items(std::tr1::get<1>(group));
00635 for (item_map_type::const_iterator it = items.begin();
00636 it != items.end();
00637 ++it)
00638 {
00639 item_type const& item = it->second;
00640 std::string const& key(std::tr1::get<0>(item));
00641 std::string const& value(std::tr1::get<1>(item));
00642 std::string const& comment(std::tr1::get<2>(item));
00643
00644 if (comment.length() > 0)
00645 print_comment(comment, stream);
00646
00647 stream << key << '=' << value << '\n';
00648 }
00649 }
00650
00651 return stream;
00652 }
00653
00654 private:
00661 const group_type *
00662 find_group (std::string const& group) const;
00663
00670 group_type *
00671 find_group (std::string const& group);
00672
00680 const item_type *
00681 find_item (std::string const& group,
00682 std::string const& key) const;
00683
00691 item_type *
00692 find_item (std::string const& group,
00693 std::string const& key);
00694
00703 void
00704 check_priority (std::string const& group,
00705 std::string const& key,
00706 priority priority,
00707 bool valid) const;
00708
00716 static void
00717 print_comment (std::string const& comment,
00718 std::ostream& stream);
00719
00721 group_map_type groups;
00723 char separator;
00724 };
00725
00726 }
00727
00728 #endif
00729
00730
00731
00732
00733
00734