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 DEPRECATED_KEY,
00079 DEPRECATED_KEY_NL,
00080 DISALLOWED_KEY,
00081 DISALLOWED_KEY_NL,
00082 DUPLICATE_GROUP,
00083 DUPLICATE_KEY,
00084 INVALID_GROUP,
00085 INVALID_LINE,
00086 MISSING_KEY,
00087 MISSING_KEY_NL,
00088 NO_GROUP,
00089 NO_KEY,
00090 OBSOLETE_KEY,
00091 OBSOLETE_KEY_NL,
00092 PASSTHROUGH_G,
00093 PASSTHROUGH_GK,
00094 PASSTHROUGH_LG,
00095 PASSTHROUGH_LGK
00096 };
00097
00099 typedef parse_error<error_code> error;
00100
00102 keyfile ();
00103
00109 keyfile (std::string const& file);
00110
00116 keyfile (std::istream& stream);
00117
00119 virtual ~keyfile ();
00120
00127 string_list
00128 get_groups () const;
00129
00137 string_list
00138 get_keys (std::string const& group) const;
00139
00146 bool
00147 has_group (std::string const& group) const;
00148
00156 bool
00157 has_key (std::string const& group,
00158 std::string const& key) const;
00159
00167 void
00168 set_group (std::string const& group,
00169 std::string const& comment);
00170
00179 void
00180 set_group (std::string const& group,
00181 std::string const& comment,
00182 unsigned int line);
00183
00190 std::string
00191 get_comment (std::string const& group) const;
00192
00200 std::string
00201 get_comment (std::string const& group,
00202 std::string const& key) const;
00203
00210 unsigned int
00211 get_line (std::string const& group) const;
00212
00220 unsigned int
00221 get_line (std::string const& group,
00222 std::string const& key) const;
00223
00234 template <typename T>
00235 bool
00236 get_value (std::string const& group,
00237 std::string const& key,
00238 T& value) const
00239 {
00240 log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00241 << ", key=" << key << std::endl;
00242 const item_type *found_item = find_item(group, key);
00243 if (found_item)
00244 {
00245 std::string const& strval(std::tr1::get<1>(*found_item));
00246 try
00247 {
00248 parse_value(strval, value);
00249 return true;
00250 }
00251 catch (parse_value_error const& e)
00252 {
00253 unsigned int line = get_line(group, key);
00254 if (line)
00255 {
00256 error ep(line, group, key, PASSTHROUGH_LGK, e);
00257 log_exception_warning(ep);
00258 }
00259 else
00260 {
00261 error ep(group, key, PASSTHROUGH_GK, e);
00262 log_exception_warning(ep);
00263 }
00264 return false;
00265 }
00266 }
00267 log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00268 return false;
00269 }
00270
00283 template <typename T>
00284 bool
00285 get_value (std::string const& group,
00286 std::string const& key,
00287 priority priority,
00288 T& value) const
00289 {
00290 bool status = get_value(group, key, value);
00291 check_priority(group, key, priority, status);
00292 return status;
00293 }
00294
00304 bool
00305 get_locale_string (std::string const& group,
00306 std::string const& key,
00307 std::string& value) const;
00308
00320 bool
00321 get_locale_string (std::string const& group,
00322 std::string const& key,
00323 priority priority,
00324 std::string& value) const;
00325
00336 bool
00337 get_locale_string (std::string const& group,
00338 std::string const& key,
00339 std::string const& locale,
00340 std::string& value) const;
00341
00355 bool
00356 get_locale_string (std::string const& group,
00357 std::string const& key,
00358 std::string const& locale,
00359 priority priority,
00360 std::string& value) const;
00361
00374 template <typename C>
00375 bool
00376 get_list_value (std::string const& group,
00377 std::string const& key,
00378 C& container) const
00379 {
00380 std::string item_value;
00381 if (get_value(group, key, item_value))
00382 {
00383 string_list items = split_string(item_value,
00384 std::string(1, this->separator));
00385 for (string_list::const_iterator pos = items.begin();
00386 pos != items.end();
00387 ++pos
00388 )
00389 {
00390 typename C::value_type tmp;
00391
00392 try
00393 {
00394 parse_value(*pos, tmp);
00395 }
00396 catch (parse_value_error const& e)
00397 {
00398 unsigned int line = get_line(group, key);
00399 if (line)
00400 {
00401 error ep(line, group, key, PASSTHROUGH_LGK, e);
00402 log_exception_warning(ep);
00403 }
00404 else
00405 {
00406 error ep(group, key, PASSTHROUGH_GK, e);
00407 log_exception_warning(ep);
00408 }
00409 return false;
00410 }
00411
00412 container.push_back(tmp);
00413 }
00414 return true;
00415 }
00416 return false;
00417 }
00418
00433 template <typename C>
00434 bool
00435 get_list_value (std::string const& group,
00436 std::string const& key,
00437 priority priority,
00438 C& container) const
00439 {
00440 bool status = get_list_value(group, key, container);
00441 check_priority(group, key, priority, status);
00442 return status;
00443 }
00444
00453 template <typename T>
00454 void
00455 set_value (std::string const& group,
00456 std::string const& key,
00457 T const& value)
00458 {
00459 set_value(group, key, value, std::string());
00460 }
00461
00471 template <typename T>
00472 void
00473 set_value (std::string const& group,
00474 std::string const& key,
00475 T const& value,
00476 std::string const& comment)
00477 {
00478 set_value(group, key, value, comment, 0);
00479 }
00480
00491 template <typename T>
00492 void
00493 set_value (std::string const& group,
00494 std::string const& key,
00495 T const& value,
00496 std::string const& comment,
00497 unsigned int line)
00498 {
00499 std::ostringstream os;
00500 os.imbue(std::locale("C"));
00501 os << std::boolalpha << value;
00502
00503 set_group(group, "");
00504 group_type *found_group = find_group(group);
00505 assert (found_group != 0);
00506
00507 item_map_type& items = std::tr1::get<1>(*found_group);
00508
00509 item_map_type::iterator pos = items.find(key);
00510 if (pos != items.end())
00511 items.erase(pos);
00512 items.insert
00513 (item_map_type::value_type(key,
00514 item_type(key, os.str(), comment, line)));
00515 }
00516
00526 template <typename I>
00527 void
00528 set_list_value (std::string const& group,
00529 std::string const& key,
00530 I begin,
00531 I end)
00532 {
00533 set_list_value(group, key, begin, end, std::string());
00534 }
00535
00546 template <typename I>
00547 void
00548 set_list_value (std::string const& group,
00549 std::string const& key,
00550 I begin,
00551 I end,
00552 std::string const& comment)
00553 {
00554 set_list_value (group, key, begin, end, comment, 0);
00555 }
00556
00568 template <typename I>
00569 void
00570 set_list_value (std::string const& group,
00571 std::string const& key,
00572 I begin,
00573 I end,
00574 std::string const& comment,
00575 unsigned int line)
00576 {
00577 std::string strval;
00578
00579 for (I pos = begin; pos != end; ++ pos)
00580 {
00581 std::ostringstream os;
00582 os.imbue(std::locale("C"));
00583 os << std::boolalpha << *pos;
00584 if (os)
00585 {
00586 strval += os.str();
00587 if (pos + 1 != end)
00588 strval += this->separator;
00589 }
00590 }
00591
00592 set_value (group, key, strval, comment, line);
00593 }
00594
00600 void
00601 remove_group (std::string const& group);
00602
00609 void
00610 remove_key (std::string const& group,
00611 std::string const& key);
00612
00619 keyfile&
00620 operator += (keyfile const& rhs);
00621
00629 friend keyfile
00630 operator + (keyfile const& lhs,
00631 keyfile const& rhs);
00632
00636 template <class charT, class traits>
00637 friend
00638 std::basic_istream<charT,traits>&
00639 operator >> (std::basic_istream<charT,traits>& stream,
00640 keyfile& kf)
00641 {
00642 keyfile tmp;
00643 size_t linecount = 0;
00644 std::string line;
00645 std::string group;
00646 std::string comment;
00647 std::string key;
00648 std::string value;
00649
00650 while (std::getline(stream, line))
00651 {
00652 linecount++;
00653
00654 if (line.length() == 0)
00655 {
00656
00657 }
00658 else if (line[0] == '#')
00659 {
00660 if (!comment.empty())
00661 comment += '\n';
00662 comment += line.substr(1);
00663 }
00664 else if (line[0] == '[')
00665 {
00666 std::string::size_type fpos = line.find_first_of(']');
00667 std::string::size_type lpos = line.find_last_of(']');
00668 if (fpos == std::string::npos || lpos == std::string::npos ||
00669 fpos != lpos)
00670 throw error(linecount, INVALID_GROUP, line);
00671 group = line.substr(1, fpos - 1);
00672
00673 if (group.length() == 0)
00674 throw error(linecount, INVALID_GROUP, line);
00675
00676
00677 if (tmp.has_group(group))
00678 throw error(linecount, DUPLICATE_GROUP, group);
00679 else
00680 tmp.set_group(group, comment, linecount);
00681 comment.clear();
00682 }
00683 else
00684 {
00685 std::string::size_type pos = line.find_first_of('=');
00686 if (pos == std::string::npos)
00687 throw error(linecount, INVALID_LINE, line);
00688 if (pos == 0)
00689 throw error(linecount, NO_KEY, line);
00690 key = line.substr(0, pos);
00691 if (pos == line.length() - 1)
00692 value = "";
00693 else
00694 value = line.substr(pos + 1);
00695
00696
00697 if (group.empty())
00698 throw error(linecount, NO_GROUP, line);
00699
00700
00701 if (tmp.has_key(group, key))
00702 throw error(linecount, group, DUPLICATE_KEY, key);
00703 else
00704 tmp.set_value(group, key, value, comment, linecount);
00705 comment.clear();
00706 }
00707 }
00708
00709 kf += tmp;
00710
00711 return stream;
00712 }
00713
00717 template <class charT, class traits>
00718 friend
00719 std::basic_ostream<charT,traits>&
00720 operator << (std::basic_ostream<charT,traits>& stream,
00721 keyfile const& kf)
00722 {
00723 unsigned int group_count = 0;
00724
00725 for (group_map_type::const_iterator gp = kf.groups.begin();
00726 gp != kf.groups.end();
00727 ++gp, ++group_count)
00728 {
00729 if (group_count > 0)
00730 stream << '\n';
00731
00732 group_type const& group = gp->second;
00733 std::string const& groupname = std::tr1::get<0>(group);
00734 std::string const& comment = std::tr1::get<2>(group);
00735
00736 if (comment.length() > 0)
00737 print_comment(comment, stream);
00738
00739 stream << '[' << groupname << ']' << '\n';
00740
00741 item_map_type const& items(std::tr1::get<1>(group));
00742 for (item_map_type::const_iterator it = items.begin();
00743 it != items.end();
00744 ++it)
00745 {
00746 item_type const& item = it->second;
00747 std::string const& key(std::tr1::get<0>(item));
00748 std::string const& value(std::tr1::get<1>(item));
00749 std::string const& comment(std::tr1::get<2>(item));
00750
00751 if (comment.length() > 0)
00752 print_comment(comment, stream);
00753
00754 stream << key << '=' << value << '\n';
00755 }
00756 }
00757
00758 return stream;
00759 }
00760
00761 private:
00768 const group_type *
00769 find_group (std::string const& group) const;
00770
00777 group_type *
00778 find_group (std::string const& group);
00779
00787 const item_type *
00788 find_item (std::string const& group,
00789 std::string const& key) const;
00790
00798 item_type *
00799 find_item (std::string const& group,
00800 std::string const& key);
00801
00810 void
00811 check_priority (std::string const& group,
00812 std::string const& key,
00813 priority priority,
00814 bool valid) const;
00815
00823 static void
00824 print_comment (std::string const& comment,
00825 std::ostream& stream);
00826
00828 group_map_type groups;
00830 char separator;
00831
00832 public:
00845 template<class C, typename T>
00846 static void
00847 set_object_value (C const& object,
00848 T (C::* method)() const,
00849 keyfile& keyfile,
00850 std::string const& group,
00851 std::string const& key)
00852 {
00853 try
00854 {
00855 keyfile.set_value(group, key, (object.*method)());
00856 }
00857 catch (std::runtime_error const& e)
00858 {
00859 throw error(group, key, PASSTHROUGH_GK, e);
00860 }
00861 }
00862
00875 template<class C, typename T>
00876 static void
00877 set_object_value (C const& object,
00878 T const& (C::* method)() const,
00879 keyfile& keyfile,
00880 std::string const& group,
00881 std::string const& key)
00882 {
00883 try
00884 {
00885 keyfile.set_value(group, key, (object.*method)());
00886 }
00887 catch (std::runtime_error const& e)
00888 {
00889 throw error(group, key, PASSTHROUGH_GK, e);
00890 }
00891 }
00892
00906 template<class C, typename T>
00907 static void
00908 set_object_list_value (C const& object,
00909 T (C::* method)() const,
00910 keyfile& keyfile,
00911 std::string const& group,
00912 std::string const& key)
00913 {
00914 try
00915 {
00916 keyfile.set_list_value(group, key,
00917 (object.*method)().begin(),
00918 (object.*method)().end());
00919 }
00920 catch (std::runtime_error const& e)
00921 {
00922 throw error(group, key, PASSTHROUGH_GK, e);
00923 }
00924 }
00925
00940 template<class C, typename T>
00941 static void
00942 set_object_list_value (C const& object,
00943 T const& (C::* method)() const,
00944 keyfile& keyfile,
00945 std::string const& group,
00946 std::string const& key)
00947 {
00948 try
00949 {
00950 keyfile.set_list_value(group, key,
00951 (object.*method)().begin(),
00952 (object.*method)().end());
00953 }
00954 catch (std::runtime_error const& e)
00955 {
00956 throw error(group, key, PASSTHROUGH_GK, e);
00957 }
00958 }
00959
00974 template<class C, typename T>
00975 static void
00976 get_object_value (C& object,
00977 void (C::* method)(T param),
00978 keyfile const& keyfile,
00979 std::string const& group,
00980 std::string const& key,
00981 keyfile::priority priority)
00982 {
00983 try
00984 {
00985 T value;
00986 if (keyfile.get_value(group, key, priority, value))
00987 (object.*method)(value);
00988 }
00989 catch (std::runtime_error const& e)
00990 {
00991 unsigned int line = keyfile.get_line(group, key);
00992 if (line)
00993 throw error(line, group, key, PASSTHROUGH_LGK, e);
00994 else
00995 throw error(group, key, PASSTHROUGH_GK, e);
00996 }
00997 }
00998
01013 template<class C, typename T>
01014 static void
01015 get_object_value (C& object,
01016 void (C::* method)(T const& param),
01017 keyfile const& keyfile,
01018 std::string const& group,
01019 std::string const& key,
01020 keyfile::priority priority)
01021 {
01022 try
01023 {
01024 T value;
01025 if (keyfile.get_value(group, key, priority, value))
01026 (object.*method)(value);
01027 }
01028 catch (std::runtime_error const& e)
01029 {
01030 unsigned int line = keyfile.get_line(group, key);
01031 if (line)
01032 throw error(line, group, key, PASSTHROUGH_LGK, e);
01033 else
01034 throw error(group, key, PASSTHROUGH_GK, e);
01035 }
01036 }
01037
01052 template<class C, typename T>
01053 static void
01054 get_object_list_value (C& object,
01055 void (C::* method)(T param),
01056 keyfile const& keyfile,
01057 std::string const& group,
01058 std::string const& key,
01059 keyfile::priority priority)
01060 {
01061 try
01062 {
01063 T value;
01064 if (keyfile.get_list_value(group, key, priority, value))
01065 (object.*method)(value);
01066 }
01067 catch (std::runtime_error const& e)
01068 {
01069 unsigned int line = keyfile.get_line(group, key);
01070 if (line)
01071 throw error(line, group, key, PASSTHROUGH_LGK, e);
01072 else
01073 throw error(group, key, PASSTHROUGH_GK, e);
01074 throw error(keyfile.get_line(group, key),
01075 group, key, e);
01076 }
01077 }
01078
01094 template<class C, typename T>
01095 static void
01096 get_object_list_value (C& object,
01097 void (C::* method)(T const& param),
01098 keyfile const& keyfile,
01099 std::string const& group,
01100 std::string const& key,
01101 keyfile::priority priority)
01102 {
01103 try
01104 {
01105 T value;
01106 if (keyfile.get_list_value(group, key, priority, value))
01107 (object.*method)(value);
01108 }
01109 catch (std::runtime_error const& e)
01110 {
01111 unsigned int line = keyfile.get_line(group, key);
01112 if (line)
01113 throw error(line, group, key, PASSTHROUGH_LGK, e);
01114 else
01115 throw error(group, key, PASSTHROUGH_GK, e);
01116 throw error(keyfile.get_line(group, key),
01117 group, key, e);
01118 }
01119 }
01120 };
01121
01122 }
01123
01124 #endif
01125
01126
01127
01128
01129
01130