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 enum error_code
00076 {
00077 BAD_FILE,
00078 DISALLOWED_KEY,
00079 DISALLOWED_KEY_NL,
00080 DUPLICATE_GROUP,
00081 DUPLICATE_KEY,
00082 INVALID_GROUP,
00083 INVALID_LINE,
00084 MISSING_KEY,
00085 NO_GROUP,
00086 NO_KEY,
00087 PASSTHROUGH_GK,
00088 PASSTHROUGH_LGK
00089 };
00090
00092 typedef parse_error<error_code> error;
00093
00095 keyfile ();
00096
00102 keyfile (std::string const& file);
00103
00109 keyfile (std::istream& stream);
00110
00112 virtual ~keyfile ();
00113
00120 string_list
00121 get_groups () const;
00122
00130 string_list
00131 get_keys (std::string const& group) const;
00132
00139 bool
00140 has_group (std::string const& group) const;
00141
00149 bool
00150 has_key (std::string const& group,
00151 std::string const& key) const;
00152
00160 void
00161 set_group (std::string const& group,
00162 std::string const& comment);
00163
00164 private:
00173 void
00174 set_group (std::string const& group,
00175 std::string const& comment,
00176 unsigned int line);
00177
00178 public:
00185 std::string
00186 get_comment (std::string const& group) const;
00187
00195 std::string
00196 get_comment (std::string const& group,
00197 std::string const& key) const;
00198
00205 unsigned int
00206 get_line (std::string const& group) const;
00207
00215 unsigned int
00216 get_line (std::string const& group,
00217 std::string const& key) const;
00218
00229 template <typename T>
00230 bool
00231 get_value (std::string const& group,
00232 std::string const& key,
00233 T& value) const
00234 {
00235 log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00236 << ", key=" << key << std::endl;
00237 const item_type *found_item = find_item(group, key);
00238 if (found_item)
00239 {
00240 std::string const& strval(std::tr1::get<1>(*found_item));
00241 try
00242 {
00243 parse_value(strval, value);
00244 return true;
00245 }
00246 catch (parse_value_error const& e)
00247 {
00248 unsigned int line = get_line(group, key);
00249 if (line)
00250 {
00251 error ep(line, group, key, PASSTHROUGH_LGK, e.what());
00252 log_warning() << ep.what() << std::endl;
00253 }
00254 else
00255 {
00256 error ep(group, key, PASSTHROUGH_GK, e.what());
00257 log_warning() << ep.what() << std::endl;
00258 }
00259 return false;
00260 }
00261 }
00262 log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00263 return false;
00264 }
00265
00278 template <typename T>
00279 bool
00280 get_value (std::string const& group,
00281 std::string const& key,
00282 priority priority,
00283 T& value) const
00284 {
00285 bool status = get_value(group, key, value);
00286 check_priority(group, key, priority, status);
00287 return status;
00288 }
00289
00299 bool
00300 get_locale_string (std::string const& group,
00301 std::string const& key,
00302 std::string& value) const;
00303
00315 bool
00316 get_locale_string (std::string const& group,
00317 std::string const& key,
00318 priority priority,
00319 std::string& value) const;
00320
00331 bool
00332 get_locale_string (std::string const& group,
00333 std::string const& key,
00334 std::string const& locale,
00335 std::string& value) const;
00336
00350 bool
00351 get_locale_string (std::string const& group,
00352 std::string const& key,
00353 std::string const& locale,
00354 priority priority,
00355 std::string& value) const;
00356
00369 template <typename C>
00370 bool
00371 get_list_value (std::string const& group,
00372 std::string const& key,
00373 C& container) const
00374 {
00375 std::string item_value;
00376 if (get_value(group, key, item_value))
00377 {
00378 string_list items = split_string(item_value,
00379 std::string(1, this->separator));
00380 for (string_list::const_iterator pos = items.begin();
00381 pos != items.end();
00382 ++pos
00383 )
00384 {
00385 typename C::value_type tmp;
00386
00387 try
00388 {
00389 parse_value(*pos, tmp);
00390 }
00391 catch (parse_value_error const& e)
00392 {
00393 unsigned int line = get_line(group, key);
00394 if (line)
00395 {
00396 error ep(line, group, key, PASSTHROUGH_LGK, e.what());
00397 log_warning() << ep.what() << std::endl;
00398 }
00399 else
00400 {
00401 error ep(group, key, PASSTHROUGH_GK, e.what());
00402 log_warning() << ep.what() << std::endl;
00403 }
00404 return false;
00405 }
00406
00407 container.push_back(tmp);
00408 }
00409 return true;
00410 }
00411 return false;
00412 }
00413
00428 template <typename C>
00429 bool
00430 get_list_value (std::string const& group,
00431 std::string const& key,
00432 priority priority,
00433 C& container) const
00434 {
00435 bool status = get_list_value(group, key, container);
00436 check_priority(group, key, priority, status);
00437 return status;
00438 }
00439
00448 template <typename T>
00449 void
00450 set_value (std::string const& group,
00451 std::string const& key,
00452 T const& value)
00453 {
00454 set_value(group, key, value, std::string());
00455 }
00456
00466 template <typename T>
00467 void
00468 set_value (std::string const& group,
00469 std::string const& key,
00470 T const& value,
00471 std::string const& comment)
00472 {
00473 std::ostringstream os;
00474 os.imbue(std::locale("C"));
00475 os << std::boolalpha << value;
00476
00477 set_value(group, key, os.str(), comment, 0);
00478 }
00479
00480 private:
00491 void
00492 set_value (std::string const& group,
00493 std::string const& key,
00494 std::string const& value,
00495 std::string const& comment,
00496 unsigned int line)
00497 {
00498 set_group(group, "");
00499 group_type *found_group = find_group(group);
00500 assert (found_group != 0);
00501
00502 item_map_type& items = std::tr1::get<1>(*found_group);
00503
00504 item_map_type::iterator pos = items.find(key);
00505 if (pos != items.end())
00506 items.erase(pos);
00507 items.insert
00508 (item_map_type::value_type(key,
00509 item_type(key, value, comment, line)));
00510 }
00511
00512 public:
00522 template <typename I>
00523 void
00524 set_list_value (std::string const& group,
00525 std::string const& key,
00526 I begin,
00527 I end)
00528 {
00529 set_list_value(group, key, begin, end, std::string());
00530 }
00531
00542 template <typename I>
00543 void
00544 set_list_value (std::string const& group,
00545 std::string const& key,
00546 I begin,
00547 I end,
00548 std::string const& comment)
00549 {
00550 std::string strval;
00551
00552 for (I pos = begin; pos != end; ++ pos)
00553 {
00554 std::ostringstream os;
00555 os.imbue(std::locale("C"));
00556 os << std::boolalpha << *pos;
00557 if (os)
00558 {
00559 strval += os.str();
00560 if (pos + 1 != end)
00561 strval += this->separator;
00562 }
00563 }
00564
00565 set_value (group, key, strval, comment);
00566 }
00567
00573 void
00574 remove_group (std::string const& group);
00575
00582 void
00583 remove_key (std::string const& group,
00584 std::string const& key);
00585
00592 keyfile&
00593 operator += (keyfile const& rhs);
00594
00602 friend keyfile
00603 operator + (keyfile const& lhs,
00604 keyfile const& rhs);
00605
00609 template <class charT, class traits>
00610 friend
00611 std::basic_istream<charT,traits>&
00612 operator >> (std::basic_istream<charT,traits>& stream,
00613 keyfile& kf)
00614 {
00615 keyfile tmp;
00616 size_t linecount = 0;
00617 std::string line;
00618 std::string group;
00619 std::string comment;
00620 std::string key;
00621 std::string value;
00622
00623 while (std::getline(stream, line))
00624 {
00625 linecount++;
00626
00627 if (line.length() == 0)
00628 {
00629
00630 }
00631 else if (line[0] == '#')
00632 {
00633 if (!comment.empty())
00634 comment += '\n';
00635 comment += line.substr(1);
00636 }
00637 else if (line[0] == '[')
00638 {
00639 std::string::size_type fpos = line.find_first_of(']');
00640 std::string::size_type lpos = line.find_last_of(']');
00641 if (fpos == std::string::npos || lpos == std::string::npos ||
00642 fpos != lpos)
00643 {
00644 throw error(linecount, INVALID_GROUP, line);
00645 }
00646 group = line.substr(1, fpos - 1);
00647
00648 if (group.length() == 0)
00649 {
00650 throw error(linecount, INVALID_GROUP, line);
00651 }
00652
00653
00654 if (tmp.has_group(group))
00655 {
00656 error e(linecount, DUPLICATE_GROUP, group);
00657 log_warning() << e.what() << std::endl;
00658 }
00659 else
00660 tmp.set_group(group, comment, linecount);
00661 comment.clear();
00662 }
00663 else
00664 {
00665 std::string::size_type pos = line.find_first_of('=');
00666 if (pos == std::string::npos)
00667 {
00668 throw error(linecount, INVALID_LINE, line);
00669 }
00670 if (pos == 0)
00671 {
00672 throw error(linecount, NO_KEY, line);
00673 }
00674 key = line.substr(0, pos);
00675 if (pos == line.length() - 1)
00676 value = "";
00677 else
00678 value = line.substr(pos + 1);
00679
00680
00681 if (group.empty())
00682 {
00683 throw error(linecount, NO_GROUP, line);
00684 }
00685
00686
00687 if (tmp.has_key(group, key))
00688 {
00689 error e(linecount, group, DUPLICATE_KEY, key);
00690 log_warning() << e.what() << std::endl;
00691 }
00692 else
00693 tmp.set_value(group, key, value, comment, linecount);
00694 comment.clear();
00695 }
00696 }
00697
00698 kf += tmp;
00699
00700 return stream;
00701 }
00702
00706 template <class charT, class traits>
00707 friend
00708 std::basic_ostream<charT,traits>&
00709 operator << (std::basic_ostream<charT,traits>& stream,
00710 keyfile const& kf)
00711 {
00712 unsigned int group_count = 0;
00713
00714 for (group_map_type::const_iterator gp = kf.groups.begin();
00715 gp != kf.groups.end();
00716 ++gp, ++group_count)
00717 {
00718 if (group_count > 0)
00719 stream << '\n';
00720
00721 group_type const& group = gp->second;
00722 std::string const& groupname = std::tr1::get<0>(group);
00723 std::string const& comment = std::tr1::get<2>(group);
00724
00725 if (comment.length() > 0)
00726 print_comment(comment, stream);
00727
00728 stream << '[' << groupname << ']' << '\n';
00729
00730 item_map_type const& items(std::tr1::get<1>(group));
00731 for (item_map_type::const_iterator it = items.begin();
00732 it != items.end();
00733 ++it)
00734 {
00735 item_type const& item = it->second;
00736 std::string const& key(std::tr1::get<0>(item));
00737 std::string const& value(std::tr1::get<1>(item));
00738 std::string const& comment(std::tr1::get<2>(item));
00739
00740 if (comment.length() > 0)
00741 print_comment(comment, stream);
00742
00743 stream << key << '=' << value << '\n';
00744 }
00745 }
00746
00747 return stream;
00748 }
00749
00750 private:
00757 const group_type *
00758 find_group (std::string const& group) const;
00759
00766 group_type *
00767 find_group (std::string const& group);
00768
00776 const item_type *
00777 find_item (std::string const& group,
00778 std::string const& key) const;
00779
00787 item_type *
00788 find_item (std::string const& group,
00789 std::string const& key);
00790
00799 void
00800 check_priority (std::string const& group,
00801 std::string const& key,
00802 priority priority,
00803 bool valid) const;
00804
00812 static void
00813 print_comment (std::string const& comment,
00814 std::ostream& stream);
00815
00817 group_map_type groups;
00819 char separator;
00820
00821 public:
00834 template<class C, typename T>
00835 static void
00836 set_object_value (C const& object,
00837 T (C::* method)() const,
00838 keyfile& keyfile,
00839 std::string const& group,
00840 std::string const& key)
00841 {
00842 try
00843 {
00844 keyfile.set_value(group, key, (object.*method)());
00845 }
00846 catch (std::runtime_error const& e)
00847 {
00848 throw error(group, key, PASSTHROUGH_GK, e.what());
00849 }
00850 }
00851
00864 template<class C, typename T>
00865 static void
00866 set_object_value (C const& object,
00867 T const& (C::* method)() const,
00868 keyfile& keyfile,
00869 std::string const& group,
00870 std::string const& key)
00871 {
00872 try
00873 {
00874 keyfile.set_value(group, key, (object.*method)());
00875 }
00876 catch (std::runtime_error const& e)
00877 {
00878 throw error(group, key, PASSTHROUGH_GK, e.what());
00879 }
00880 }
00881
00895 template<class C, typename T>
00896 static void
00897 set_object_list_value (C const& object,
00898 T (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 (std::runtime_error const& e)
00910 {
00911 throw error(group, key, PASSTHROUGH_GK, e.what());
00912 }
00913 }
00914
00929 template<class C, typename T>
00930 static void
00931 set_object_list_value (C const& object,
00932 T const& (C::* method)() const,
00933 keyfile& keyfile,
00934 std::string const& group,
00935 std::string const& key)
00936 {
00937 try
00938 {
00939 keyfile.set_list_value(group, key,
00940 (object.*method)().begin(),
00941 (object.*method)().end());
00942 }
00943 catch (std::runtime_error const& e)
00944 {
00945 throw error(group, key, PASSTHROUGH_GK, e.what());
00946 }
00947 }
00948
00963 template<class C, typename T>
00964 static void
00965 get_object_value (C& object,
00966 void (C::* method)(T param),
00967 keyfile const& keyfile,
00968 std::string const& group,
00969 std::string const& key,
00970 keyfile::priority priority)
00971 {
00972 T value;
00973 if (keyfile.get_value(group, key, priority, value))
00974 {
00975 try
00976 {
00977 (object.*method)(value);
00978 }
00979 catch (std::runtime_error const& e)
00980 {
00981 unsigned int line = keyfile.get_line(group, key);
00982 if (line)
00983 throw error(line, group, key, PASSTHROUGH_LGK, e.what());
00984 else
00985 throw error(group, key, PASSTHROUGH_GK, e.what());
00986 }
00987 }
00988 }
00989
01004 template<class C, typename T>
01005 static void
01006 get_object_value (C& object,
01007 void (C::* method)(T const& param),
01008 keyfile const& keyfile,
01009 std::string const& group,
01010 std::string const& key,
01011 keyfile::priority priority)
01012 {
01013 T value;
01014 if (keyfile.get_value(group, key, priority, value))
01015 {
01016 try
01017 {
01018 (object.*method)(value);
01019 }
01020 catch (std::runtime_error const& e)
01021 {
01022 unsigned int line = keyfile.get_line(group, key);
01023 if (line)
01024 throw error(line, group, key, PASSTHROUGH_LGK, e.what());
01025 else
01026 throw error(group, key, PASSTHROUGH_GK, e.what());
01027 throw error(keyfile.get_line(group, key),
01028 group, key, e);
01029 }
01030 }
01031 }
01032
01047 template<class C, typename T>
01048 static void
01049 get_object_list_value (C& object,
01050 void (C::* method)(T 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 (std::runtime_error const& e)
01064 {
01065 unsigned int line = keyfile.get_line(group, key);
01066 if (line)
01067 throw error(line, group, key, PASSTHROUGH_LGK, e.what());
01068 else
01069 throw error(group, key, PASSTHROUGH_GK, e.what());
01070 throw error(keyfile.get_line(group, key),
01071 group, key, e);
01072 }
01073 }
01074 }
01075
01091 template<class C, typename T>
01092 static void
01093 get_object_list_value (C& object,
01094 void (C::* method)(T const& param),
01095 keyfile const& keyfile,
01096 std::string const& group,
01097 std::string const& key,
01098 keyfile::priority priority)
01099 {
01100 T value;
01101 if (keyfile.get_list_value(group, key, priority, value))
01102 {
01103 try
01104 {
01105 (object.*method)(value);
01106 }
01107 catch (std::runtime_error const& e)
01108 {
01109 unsigned int line = keyfile.get_line(group, key);
01110 if (line)
01111 throw error(line, group, key, PASSTHROUGH_LGK, e.what());
01112 else
01113 throw error(group, key, PASSTHROUGH_GK, e.what());
01114 throw error(keyfile.get_line(group, key),
01115 group, key, e);
01116 }
01117 }
01118 }
01119 };
01120
01121 }
01122
01123 #endif
01124
01125
01126
01127
01128
01129