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/sbuild-i18n.h>
00024 #include <sbuild/sbuild-log.h>
00025 #include <sbuild/sbuild-parse-error.h>
00026 #include <sbuild/sbuild-parse-value.h>
00027 #include <sbuild/sbuild-types.h>
00028 #include <sbuild/sbuild-tr1types.h>
00029 #include <sbuild/sbuild-util.h>
00030
00031 #include <cassert>
00032 #include <map>
00033 #include <string>
00034 #include <sstream>
00035
00036 #include <boost/format.hpp>
00037
00038 namespace sbuild
00039 {
00040
00047 class keyfile
00048 {
00049 private:
00051 typedef std::tr1::tuple<std::string,std::string,std::string,unsigned int>
00052 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,unsigned int> 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 parse_error 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
00147 private:
00156 void
00157 set_group (std::string const& group,
00158 std::string const& comment,
00159 unsigned int line);
00160
00161 public:
00168 std::string
00169 get_comment (std::string const& group) const;
00170
00178 std::string
00179 get_comment (std::string const& group,
00180 std::string const& key) const;
00181
00188 unsigned int
00189 get_line (std::string const& group) const;
00190
00198 unsigned int
00199 get_line (std::string const& group,
00200 std::string const& key) const;
00201
00212 template <typename T>
00213 bool
00214 get_value (std::string const& group,
00215 std::string const& key,
00216 T& value) const
00217 {
00218 log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00219 << ", key=" << key << std::endl;
00220 const item_type *found_item = find_item(group, key);
00221 if (found_item)
00222 {
00223 std::string const& strval(std::tr1::get<1>(*found_item));
00224 try
00225 {
00226 parse_value(strval, value);
00227 return true;
00228 }
00229 catch (parse_error const& e)
00230 {
00231 error ep(group, key, parse_error::NONE, e.what());
00232 log_warning() << ep.what() << std::endl;
00233 return false;
00234 }
00235 }
00236 log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00237 return false;
00238 }
00239
00252 template <typename T>
00253 bool
00254 get_value (std::string const& group,
00255 std::string const& key,
00256 priority priority,
00257 T& value) const
00258 {
00259 bool status = get_value(group, key, value);
00260 check_priority(group, key, priority, status);
00261 return status;
00262 }
00263
00273 bool
00274 get_locale_string (std::string const& group,
00275 std::string const& key,
00276 std::string& value) const;
00277
00289 bool
00290 get_locale_string (std::string const& group,
00291 std::string const& key,
00292 priority priority,
00293 std::string& value) const;
00294
00305 bool
00306 get_locale_string (std::string const& group,
00307 std::string const& key,
00308 std::string const& locale,
00309 std::string& value) const;
00310
00324 bool
00325 get_locale_string (std::string const& group,
00326 std::string const& key,
00327 std::string const& locale,
00328 priority priority,
00329 std::string& value) const;
00330
00343 template <typename C>
00344 bool
00345 get_list_value (std::string const& group,
00346 std::string const& key,
00347 C& container) const
00348 {
00349 std::string item_value;
00350 if (get_value(group, key, item_value))
00351 {
00352 string_list items = split_string(item_value,
00353 std::string(1, this->separator));
00354 for (string_list::const_iterator pos = items.begin();
00355 pos != items.end();
00356 ++pos
00357 )
00358 {
00359 typename C::value_type tmp;
00360
00361 try
00362 {
00363 parse_value(*pos, tmp);
00364 }
00365 catch (parse_error const& e)
00366 {
00367 error ep(group, key, parse_error::NONE, e.what());
00368 log_warning() << ep.what() << std::endl;
00369 return false;
00370 }
00371
00372 container.push_back(tmp);
00373 }
00374 return true;
00375 }
00376 return false;
00377 }
00378
00393 template <typename C>
00394 bool
00395 get_list_value (std::string const& group,
00396 std::string const& key,
00397 priority priority,
00398 C& container) const
00399 {
00400 bool status = get_list_value(group, key, container);
00401 check_priority(group, key, priority, status);
00402 return status;
00403 }
00404
00413 template <typename T>
00414 void
00415 set_value (std::string const& group,
00416 std::string const& key,
00417 T const& value)
00418 {
00419 set_value(group, key, value, std::string());
00420 }
00421
00431 template <typename T>
00432 void
00433 set_value (std::string const& group,
00434 std::string const& key,
00435 T const& value,
00436 std::string const& comment)
00437 {
00438 std::ostringstream os;
00439 os.imbue(std::locale("C"));
00440 os << std::boolalpha << value;
00441
00442 set_value(group, key, os.str(), comment, 0);
00443 }
00444
00445 private:
00456 void
00457 set_value (std::string const& group,
00458 std::string const& key,
00459 std::string const& value,
00460 std::string const& comment,
00461 unsigned int line)
00462 {
00463 set_group(group, "");
00464 group_type *found_group = find_group(group);
00465 assert (found_group != 0);
00466
00467 item_map_type& items = std::tr1::get<1>(*found_group);
00468
00469 item_map_type::iterator pos = items.find(key);
00470 if (pos != items.end())
00471 items.erase(pos);
00472 items.insert
00473 (item_map_type::value_type(key,
00474 item_type(key, value, comment, line)));
00475 }
00476
00477 public:
00487 template <typename I>
00488 void
00489 set_list_value (std::string const& group,
00490 std::string const& key,
00491 I begin,
00492 I end)
00493 {
00494 set_list_value(group, key, begin, end, std::string());
00495 }
00496
00507 template <typename I>
00508 void
00509 set_list_value (std::string const& group,
00510 std::string const& key,
00511 I begin,
00512 I end,
00513 std::string const& comment)
00514 {
00515 std::string strval;
00516
00517 for (I pos = begin; pos != end; ++ pos)
00518 {
00519 std::ostringstream os;
00520 os.imbue(std::locale("C"));
00521 os << std::boolalpha << *pos;
00522 if (os)
00523 {
00524 strval += os.str();
00525 if (pos + 1 != end)
00526 strval += this->separator;
00527 }
00528 }
00529
00530 set_value (group, key, strval, comment);
00531 }
00532
00538 void
00539 remove_group (std::string const& group);
00540
00547 void
00548 remove_key (std::string const& group,
00549 std::string const& key);
00550
00557 keyfile&
00558 operator += (keyfile const& rhs);
00559
00567 friend keyfile
00568 operator + (keyfile const& lhs,
00569 keyfile const& rhs);
00570
00574 template <class charT, class traits>
00575 friend
00576 std::basic_istream<charT,traits>&
00577 operator >> (std::basic_istream<charT,traits>& stream,
00578 keyfile& kf)
00579 {
00580 keyfile tmp;
00581 size_t linecount = 0;
00582 std::string line;
00583 std::string group;
00584 std::string comment;
00585 std::string key;
00586 std::string value;
00587
00588 while (std::getline(stream, line))
00589 {
00590 linecount++;
00591
00592 if (line.length() == 0)
00593 {
00594
00595 }
00596 else if (line[0] == '#')
00597 {
00598 if (!comment.empty())
00599 comment += '\n';
00600 comment += line.substr(1);
00601 }
00602 else if (line[0] == '[')
00603 {
00604 std::string::size_type fpos = line.find_first_of(']');
00605 std::string::size_type lpos = line.find_last_of(']');
00606 if (fpos == std::string::npos || lpos == std::string::npos ||
00607 fpos != lpos)
00608 {
00609 throw error(linecount, parse_error::INVALID_GROUP, line);
00610 }
00611 group = line.substr(1, fpos - 1);
00612
00613 if (group.length() == 0)
00614 {
00615 throw error(linecount, parse_error::INVALID_GROUP, line);
00616 }
00617
00618
00619 if (tmp.has_group(group))
00620 {
00621 error e(linecount, parse_error::DUPLICATE_GROUP, group);
00622 log_warning() << e.what() << std::endl;
00623 }
00624 else
00625 tmp.set_group(group, comment, linecount);
00626 comment.clear();
00627 }
00628 else
00629 {
00630 std::string::size_type pos = line.find_first_of('=');
00631 if (pos == std::string::npos)
00632 {
00633 throw error(linecount, parse_error::INVALID_LINE, line);
00634 }
00635 if (pos == 0)
00636 {
00637 throw error(linecount, parse_error::NO_KEY, line);
00638 }
00639 key = line.substr(0, pos);
00640 if (pos == line.length() - 1)
00641 value = "";
00642 else
00643 value = line.substr(pos + 1);
00644
00645
00646 if (group.empty())
00647 {
00648 throw error(linecount, parse_error::NO_GROUP, line);
00649 }
00650
00651
00652 if (tmp.has_key(group, key))
00653 {
00654 error e(linecount, group, parse_error::DUPLICATE_KEY, key);
00655 log_warning() << e.what() << std::endl;
00656 }
00657 else
00658 tmp.set_value(group, key, value, comment, linecount);
00659 comment.clear();
00660 }
00661 }
00662
00663 kf += tmp;
00664
00665 return stream;
00666 }
00667
00671 template <class charT, class traits>
00672 friend
00673 std::basic_ostream<charT,traits>&
00674 operator << (std::basic_ostream<charT,traits>& stream,
00675 keyfile const& kf)
00676 {
00677 unsigned int group_count = 0;
00678
00679 for (group_map_type::const_iterator gp = kf.groups.begin();
00680 gp != kf.groups.end();
00681 ++gp, ++group_count)
00682 {
00683 if (group_count > 0)
00684 stream << '\n';
00685
00686 group_type const& group = gp->second;
00687 std::string const& groupname = std::tr1::get<0>(group);
00688 std::string const& comment = std::tr1::get<2>(group);
00689
00690 if (comment.length() > 0)
00691 print_comment(comment, stream);
00692
00693 stream << '[' << groupname << ']' << '\n';
00694
00695 item_map_type const& items(std::tr1::get<1>(group));
00696 for (item_map_type::const_iterator it = items.begin();
00697 it != items.end();
00698 ++it)
00699 {
00700 item_type const& item = it->second;
00701 std::string const& key(std::tr1::get<0>(item));
00702 std::string const& value(std::tr1::get<1>(item));
00703 std::string const& comment(std::tr1::get<2>(item));
00704
00705 if (comment.length() > 0)
00706 print_comment(comment, stream);
00707
00708 stream << key << '=' << value << '\n';
00709 }
00710 }
00711
00712 return stream;
00713 }
00714
00715 private:
00722 const group_type *
00723 find_group (std::string const& group) const;
00724
00731 group_type *
00732 find_group (std::string const& group);
00733
00741 const item_type *
00742 find_item (std::string const& group,
00743 std::string const& key) const;
00744
00752 item_type *
00753 find_item (std::string const& group,
00754 std::string const& key);
00755
00764 void
00765 check_priority (std::string const& group,
00766 std::string const& key,
00767 priority priority,
00768 bool valid) const;
00769
00777 static void
00778 print_comment (std::string const& comment,
00779 std::ostream& stream);
00780
00782 group_map_type groups;
00784 char separator;
00785
00786 public:
00799 template<class C, typename T>
00800 static void
00801 set_object_value (C const& object,
00802 T (C::* method)() const,
00803 keyfile& keyfile,
00804 std::string const& group,
00805 std::string const& key)
00806 {
00807 try
00808 {
00809 keyfile.set_value(group, key, (object.*method)());
00810 }
00811 catch (runtime_error const& e)
00812 {
00813 throw parse_error(group, key, parse_error::NONE, e.what());
00814 }
00815 }
00816
00829 template<class C, typename T>
00830 static void
00831 set_object_value (C const& object,
00832 T const& (C::* method)() const,
00833 keyfile& keyfile,
00834 std::string const& group,
00835 std::string const& key)
00836 {
00837 try
00838 {
00839 keyfile.set_value(group, key, (object.*method)());
00840 }
00841 catch (runtime_error const& e)
00842 {
00843 throw parse_error(group, key, parse_error::NONE, e.what());
00844 }
00845 }
00846
00861 template<class C, typename T>
00862 static void
00863 set_object_list_value (C const& object,
00864 T (C::* method)() const,
00865 keyfile& keyfile,
00866 std::string const& group,
00867 std::string const& key)
00868 {
00869 try
00870 {
00871 keyfile.set_list_value(group, key,
00872 (object.*method)().begin(),
00873 (object.*method)().end());
00874 }
00875 catch (runtime_error const& e)
00876 {
00877 throw parse_error(group, key, parse_error::NONE, e.what());
00878 }
00879 }
00880
00895 template<class C, typename T>
00896 static void
00897 set_object_list_value (C const& object,
00898 T const& (C::* method)() const,
00899 keyfile& keyfile,
00900 std::string const& group,
00901 std::string const& key)
00902 {
00903 try
00904 {
00905 keyfile.set_list_value(group, key,
00906 (object.*method)().begin(),
00907 (object.*method)().end());
00908 }
00909 catch (runtime_error const& e)
00910 {
00911 throw parse_error(group, key, parse_error::NONE, e.what());
00912 }
00913 }
00914
00930 template<class C, typename T>
00931 static void
00932 get_object_value (C& object,
00933 void (C::* method)(T param),
00934 keyfile const& keyfile,
00935 std::string const& group,
00936 std::string const& key,
00937 keyfile::priority priority)
00938 {
00939 T value;
00940 if (keyfile.get_value(group, key, priority, value))
00941 {
00942 try
00943 {
00944 (object.*method)(value);
00945 }
00946 catch (runtime_error const& e)
00947 {
00948 throw parse_error(keyfile.get_line(group, key),
00949 group, key, parse_error::NONE, e.what());
00950 }
00951 }
00952 }
00953
00969 template<class C, typename T>
00970 static void
00971 get_object_value (C& object,
00972 void (C::* method)(T const& param),
00973 keyfile const& keyfile,
00974 std::string const& group,
00975 std::string const& key,
00976 keyfile::priority priority)
00977 {
00978 T value;
00979 if (keyfile.get_value(group, key, priority, value))
00980 {
00981 try
00982 {
00983 (object.*method)(value);
00984 }
00985 catch (runtime_error const& e)
00986 {
00987 throw parse_error(keyfile.get_line(group, key),
00988 group, key, parse_error::NONE, e.what());
00989 }
00990 }
00991 }
00992
01008 template<class C, typename T>
01009 static void
01010 get_object_list_value (C& object,
01011 void (C::* method)(T param),
01012 keyfile const& keyfile,
01013 std::string const& group,
01014 std::string const& key,
01015 keyfile::priority priority)
01016 {
01017 T value;
01018 if (keyfile.get_list_value(group, key, priority, value))
01019 {
01020 try
01021 {
01022 (object.*method)(value);
01023 }
01024 catch (runtime_error const& e)
01025 {
01026 throw parse_error(keyfile.get_line(group, key),
01027 group, key, parse_error::NONE, e.what());
01028 }
01029 }
01030 }
01031
01047 template<class C, typename T>
01048 static void
01049 get_object_list_value (C& object,
01050 void (C::* method)(T const& param),
01051 keyfile const& keyfile,
01052 std::string const& group,
01053 std::string const& key,
01054 keyfile::priority priority)
01055 {
01056 T value;
01057 if (keyfile.get_list_value(group, key, priority, value))
01058 {
01059 try
01060 {
01061 (object.*method)(value);
01062 }
01063 catch (runtime_error const& e)
01064 {
01065 throw parse_error(keyfile.get_line(group, key),
01066 group, key, parse_error::NONE, e.what());
01067 }
01068 }
01069 }
01070 };
01071
01072 }
01073
01074 #endif
01075
01076
01077
01078
01079
01080