00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef SBUILD_BASIC_KEYFILE_H
00020 #define SBUILD_BASIC_KEYFILE_H
00021
00022 #include <sbuild/sbuild-i18n.h>
00023 #include <sbuild/sbuild-log.h>
00024 #include <sbuild/sbuild-keyfile-base.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 {
00043 template <typename K>
00044 class basic_keyfile_parser
00045 {
00046 public:
00048 typedef keyfile_base::error error;
00049
00051 basic_keyfile_parser ():
00052 group(),
00053 group_set(false),
00054 key(),
00055 key_set(false),
00056 value(),
00057 value_set(false),
00058 comment(),
00059 comment_set(false),
00060 line_number(0)
00061 {
00062 }
00063
00065 virtual ~basic_keyfile_parser ()
00066 {
00067 }
00068
00070 typename K::group_name_type group;
00071
00073 bool group_set;
00074
00076 typename K::key_type key;
00077
00079 bool key_set;
00080
00082 typename K::value_type value;
00083
00085 bool value_set;
00086
00088 typename K::comment_type comment;
00089
00091 bool comment_set;
00092
00094 typename K::size_type line_number;
00095
00100 virtual void
00101 begin ()
00102 {
00103 line_number = 0;
00104 }
00105
00116 virtual void
00117 parse_line (std::string const& line)
00118 {
00119 ++line_number;
00120 }
00121
00126 virtual void
00127 end()
00128 {
00129 }
00130 };
00131
00137 template <typename K, typename P = basic_keyfile_parser<K> >
00138 class basic_keyfile : public keyfile_base
00139 {
00140 public:
00142 typedef typename K::group_name_type group_name_type;
00143
00145 typedef typename K::key_type key_type;
00146
00148 typedef typename K::value_type value_type;
00149
00151 typedef typename K::comment_type comment_type;
00152
00154 typedef typename K::size_type size_type;
00155
00157 typedef std::vector<group_name_type> group_list;
00158
00160 typedef std::vector<value_type> value_list;
00161
00162 private:
00164 typedef P parse_type;
00165
00167 typedef std::tr1::tuple<key_type,value_type,comment_type,size_type>
00168 item_type;
00169
00171 typedef std::map<key_type,item_type> item_map_type;
00172
00174 typedef std::tr1::tuple<group_name_type,item_map_type,comment_type,size_type> group_type;
00175
00177 typedef std::map<group_name_type,group_type> group_map_type;
00178
00180 typedef std::vector<key_type> key_list;
00181
00182 public:
00184 basic_keyfile ();
00185
00191 basic_keyfile (std::string const& file);
00192
00198 basic_keyfile (std::istream& stream);
00199
00201 virtual ~basic_keyfile ();
00202
00209 group_list
00210 get_groups () const;
00211
00219 key_list
00220 get_keys (group_name_type const& group) const;
00221
00230 void
00231 check_keys (group_name_type const& group,
00232 key_list const& keys) const;
00233
00240 bool
00241 has_group (group_name_type const& group) const;
00242
00250 bool
00251 has_key (group_name_type const& group,
00252 key_type const& key) const;
00253
00261 void
00262 set_group (group_name_type const& group,
00263 comment_type const& comment);
00264
00273 void
00274 set_group (group_name_type const& group,
00275 comment_type const& comment,
00276 size_type line);
00277
00284 comment_type
00285 get_comment (group_name_type const& group) const;
00286
00294 comment_type
00295 get_comment (group_name_type const& group,
00296 key_type const& key) const;
00297
00304 size_type
00305 get_line (group_name_type const& group) const;
00306
00314 size_type
00315 get_line (group_name_type const& group,
00316 key_type const& key) const;
00317
00328 template <typename T>
00329 bool
00330 get_value (group_name_type const& group,
00331 key_type const& key,
00332 T& value) const
00333 {
00334 log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00335 << ", key=" << key << std::endl;
00336 const item_type *found_item = find_item(group, key);
00337 if (found_item)
00338 {
00339 value_type const& strval(std::tr1::get<1>(*found_item));
00340 try
00341 {
00342 parse_value(strval, value);
00343 return true;
00344 }
00345 catch (parse_value_error const& e)
00346 {
00347 size_type line = get_line(group, key);
00348 if (line)
00349 {
00350 error ep(line, group, key, PASSTHROUGH_LGK, e);
00351 log_exception_warning(ep);
00352 }
00353 else
00354 {
00355 error ep(group, key, PASSTHROUGH_GK, e);
00356 log_exception_warning(ep);
00357 }
00358 return false;
00359 }
00360 }
00361 log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00362 return false;
00363 }
00364
00377 template <typename T>
00378 bool
00379 get_value (group_name_type const& group,
00380 key_type const& key,
00381 priority priority,
00382 T& value) const
00383 {
00384 bool status = get_value(group, key, value);
00385 check_priority(group, key, priority, status);
00386 return status;
00387 }
00388
00398 bool
00399 get_locale_string (group_name_type const& group,
00400 key_type const& key,
00401 value_type& value) const;
00402
00414 bool
00415 get_locale_string (group_name_type const& group,
00416 key_type const& key,
00417 priority priority,
00418 value_type& value) const;
00419
00430 bool
00431 get_locale_string (group_name_type const& group,
00432 key_type const& key,
00433 std::string const& locale,
00434 value_type& value) const;
00435
00449 bool
00450 get_locale_string (group_name_type const& group,
00451 key_type const& key,
00452 std::string const& locale,
00453 priority priority,
00454 value_type& value) const;
00455
00468 template <typename C>
00469 bool
00470 get_list_value (group_name_type const& group,
00471 key_type const& key,
00472 C& container) const
00473 {
00474 value_type item_value;
00475 if (get_value(group, key, item_value))
00476 {
00477 value_list items = split_string(item_value,
00478 this->separator);
00479 for (typename value_list::const_iterator pos = items.begin();
00480 pos != items.end();
00481 ++pos
00482 )
00483 {
00484 typename C::value_type tmp;
00485
00486 try
00487 {
00488 parse_value(*pos, tmp);
00489 }
00490 catch (parse_value_error const& e)
00491 {
00492 size_type line = get_line(group, key);
00493 if (line)
00494 {
00495 error ep(line, group, key, PASSTHROUGH_LGK, e);
00496 log_exception_warning(ep);
00497 }
00498 else
00499 {
00500 error ep(group, key, PASSTHROUGH_GK, e);
00501 log_exception_warning(ep);
00502 }
00503 return false;
00504 }
00505
00506 container.push_back(tmp);
00507 }
00508 return true;
00509 }
00510 return false;
00511 }
00512
00527 template <typename C>
00528 bool
00529 get_list_value (group_name_type const& group,
00530 key_type const& key,
00531 priority priority,
00532 C& container) const
00533 {
00534 bool status = get_list_value(group, key, container);
00535 check_priority(group, key, priority, status);
00536 return status;
00537 }
00538
00547 template <typename T>
00548 void
00549 set_value (group_name_type const& group,
00550 key_type const& key,
00551 T const& value)
00552 {
00553 set_value(group, key, value, comment_type());
00554 }
00555
00565 template <typename T>
00566 void
00567 set_value (group_name_type const& group,
00568 key_type const& key,
00569 T const& value,
00570 comment_type const& comment)
00571 {
00572 set_value(group, key, value, comment, 0);
00573 }
00574
00585 template <typename T>
00586 void
00587 set_value (group_name_type const& group,
00588 key_type const& key,
00589 T const& value,
00590 comment_type const& comment,
00591 size_type line)
00592 {
00593 std::ostringstream os;
00594 os.imbue(std::locale::classic());
00595 os << std::boolalpha << value;
00596
00597 set_group(group, "");
00598 group_type *found_group = find_group(group);
00599 assert (found_group != 0);
00600
00601 item_map_type& items = std::tr1::get<1>(*found_group);
00602
00603 typename item_map_type::iterator pos = items.find(key);
00604 if (pos != items.end())
00605 items.erase(pos);
00606 items.insert
00607 (typename item_map_type::value_type(key,
00608 item_type(key, os.str(),
00609 comment, line)));
00610 }
00611
00621 template <typename I>
00622 void
00623 set_list_value (group_name_type const& group,
00624 key_type const& key,
00625 I begin,
00626 I end)
00627 {
00628 set_list_value(group, key, begin, end, comment_type());
00629 }
00630
00641 template <typename I>
00642 void
00643 set_list_value (group_name_type const& group,
00644 key_type const& key,
00645 I begin,
00646 I end,
00647 comment_type const& comment)
00648 {
00649 set_list_value (group, key, begin, end, comment, 0);
00650 }
00651
00663 template <typename I>
00664 void
00665 set_list_value (group_name_type const& group,
00666 key_type const& key,
00667 I begin,
00668 I end,
00669 comment_type const& comment,
00670 size_type line)
00671 {
00672 value_type strval;
00673
00674 for (I pos = begin; pos != end; ++ pos)
00675 {
00676 std::ostringstream os;
00677 os.imbue(std::locale::classic());
00678 os << std::boolalpha << *pos;
00679 if (os)
00680 {
00681 strval += os.str();
00682 if (pos + 1 != end)
00683 strval += this->separator;
00684 }
00685 }
00686
00687 set_value (group, key, strval, comment, line);
00688 }
00689
00695 void
00696 remove_group (group_name_type const& group);
00697
00704 void
00705 remove_key (group_name_type const& group,
00706 key_type const& key);
00707
00714 basic_keyfile&
00715 operator += (basic_keyfile const& rhs);
00716
00724 template <typename _K, typename _P>
00725 friend basic_keyfile<_K, _P>
00726 operator + (basic_keyfile<_K, _P> const& lhs,
00727 basic_keyfile<_K, _P> const& rhs);
00728
00736 template <class charT, class traits>
00737 friend
00738 std::basic_istream<charT,traits>&
00739 operator >> (std::basic_istream<charT,traits>& stream,
00740 basic_keyfile& kf)
00741 {
00742 basic_keyfile tmp;
00743 parse_type state;
00744 std::string line;
00745
00746 state.begin();
00747
00748 while (std::getline(stream, line))
00749 {
00750 state.parse_line(line);
00751
00752
00753 if (state.group_set)
00754 {
00755 if (tmp.has_group(state.group))
00756 throw error(state.line_number, DUPLICATE_GROUP, state.group);
00757 else
00758 tmp.set_group(state.group, state.comment, state.line_number);
00759 }
00760
00761
00762 if (state.key_set && state.value_set)
00763 {
00764 if (tmp.has_key(state.group, state.key))
00765 throw error(state.line_number, state.group, DUPLICATE_KEY, state.key);
00766 else
00767 tmp.set_value(state.group, state.key, state.value, state.comment, state.line_number);
00768 }
00769 }
00770
00771 state.end();
00772
00773
00774 kf += tmp;
00775
00776 return stream;
00777 }
00778
00786 template <class charT, class traits>
00787 friend
00788 std::basic_ostream<charT,traits>&
00789 operator << (std::basic_ostream<charT,traits>& stream,
00790 basic_keyfile const& kf)
00791 {
00792 size_type group_count = 0;
00793
00794 for (typename group_map_type::const_iterator gp = kf.groups.begin();
00795 gp != kf.groups.end();
00796 ++gp, ++group_count)
00797 {
00798 if (group_count > 0)
00799 stream << '\n';
00800
00801 group_type const& group = gp->second;
00802 group_name_type const& groupname = std::tr1::get<0>(group);
00803 comment_type const& comment = std::tr1::get<2>(group);
00804
00805 if (comment.length() > 0)
00806 print_comment(comment, stream);
00807
00808 stream << '[' << groupname << ']' << '\n';
00809
00810 item_map_type const& items(std::tr1::get<1>(group));
00811 for (typename item_map_type::const_iterator it = items.begin();
00812 it != items.end();
00813 ++it)
00814 {
00815 item_type const& item = it->second;
00816 key_type const& key(std::tr1::get<0>(item));
00817 value_type const& value(std::tr1::get<1>(item));
00818 comment_type const& comment(std::tr1::get<2>(item));
00819
00820 if (comment.length() > 0)
00821 print_comment(comment, stream);
00822
00823 stream << key << '=' << value << '\n';
00824 }
00825 }
00826
00827 return stream;
00828 }
00829
00830 private:
00837 const group_type *
00838 find_group (group_name_type const& group) const;
00839
00846 group_type *
00847 find_group (group_name_type const& group);
00848
00856 const item_type *
00857 find_item (group_name_type const& group,
00858 key_type const& key) const;
00859
00867 item_type *
00868 find_item (group_name_type const& group,
00869 key_type const& key);
00870
00879 void
00880 check_priority (group_name_type const& group,
00881 key_type const& key,
00882 priority priority,
00883 bool valid) const;
00884
00896 static void
00897 print_comment (comment_type const& comment,
00898 std::ostream& stream);
00899
00901 group_map_type groups;
00903 value_type separator;
00904
00905 public:
00918 template<class C, typename T>
00919 static void
00920 set_object_value (C const& object,
00921 T (C::* method)() const,
00922 basic_keyfile& basic_keyfile,
00923 group_name_type const& group,
00924 key_type const& key)
00925 {
00926 try
00927 {
00928 if (method)
00929 basic_keyfile.set_value(group, key, (object.*method)());
00930 }
00931 catch (std::runtime_error const& e)
00932 {
00933 throw error(group, key, PASSTHROUGH_GK, e);
00934 }
00935 }
00936
00949 template<class C, typename T>
00950 static void
00951 set_object_value (C const& object,
00952 T const& (C::* method)() const,
00953 basic_keyfile& basic_keyfile,
00954 group_name_type const& group,
00955 key_type const& key)
00956 {
00957 try
00958 {
00959 if (method)
00960 basic_keyfile.set_value(group, key, (object.*method)());
00961 }
00962 catch (std::runtime_error const& e)
00963 {
00964 throw error(group, key, PASSTHROUGH_GK, e);
00965 }
00966 }
00967
00981 template<class C, typename T>
00982 static void
00983 set_object_list_value (C const& object,
00984 T (C::* method)() const,
00985 basic_keyfile& basic_keyfile,
00986 group_name_type const& group,
00987 key_type const& key)
00988 {
00989 try
00990 {
00991 if (method)
00992 basic_keyfile.set_list_value(group, key,
00993 (object.*method)().begin(),
00994 (object.*method)().end());
00995 }
00996 catch (std::runtime_error const& e)
00997 {
00998 throw error(group, key, PASSTHROUGH_GK, e);
00999 }
01000 }
01001
01016 template<class C, typename T>
01017 static void
01018 set_object_list_value (C const& object,
01019 T const& (C::* method)() const,
01020 basic_keyfile& basic_keyfile,
01021 group_name_type const& group,
01022 key_type const& key)
01023 {
01024 try
01025 {
01026 if (method)
01027 basic_keyfile.set_list_value(group, key,
01028 (object.*method)().begin(),
01029 (object.*method)().end());
01030 }
01031 catch (std::runtime_error const& e)
01032 {
01033 throw error(group, key, PASSTHROUGH_GK, e);
01034 }
01035 }
01036
01051 template<class C, typename T>
01052 static void
01053 get_object_value (C& object,
01054 void (C::* method)(T param),
01055 basic_keyfile const& basic_keyfile,
01056 group_name_type const& group,
01057 key_type const& key,
01058 basic_keyfile::priority priority)
01059 {
01060 try
01061 {
01062 T value;
01063 if (basic_keyfile.get_value(group, key, priority, value)
01064 && method)
01065 (object.*method)(value);
01066 }
01067 catch (std::runtime_error const& e)
01068 {
01069 size_type line = basic_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 }
01075 }
01076
01091 template<class C, typename T>
01092 static void
01093 get_object_value (C& object,
01094 void (C::* method)(T const& param),
01095 basic_keyfile const& basic_keyfile,
01096 group_name_type const& group,
01097 key_type const& key,
01098 basic_keyfile::priority priority)
01099 {
01100 try
01101 {
01102 T value;
01103 if (basic_keyfile.get_value(group, key, priority, value)
01104 && method)
01105 (object.*method)(value);
01106 }
01107 catch (std::runtime_error const& e)
01108 {
01109 size_type line = basic_keyfile.get_line(group, key);
01110 if (line)
01111 throw error(line, group, key, PASSTHROUGH_LGK, e);
01112 else
01113 throw error(group, key, PASSTHROUGH_GK, e);
01114 }
01115 }
01116
01131 template<class C, typename T>
01132 static void
01133 get_object_list_value (C& object,
01134 void (C::* method)(T param),
01135 basic_keyfile const& basic_keyfile,
01136 group_name_type const& group,
01137 key_type const& key,
01138 basic_keyfile::priority priority)
01139 {
01140 try
01141 {
01142 T value;
01143 if (basic_keyfile.get_list_value(group, key, priority, value)
01144 && method)
01145 (object.*method)(value);
01146 }
01147 catch (std::runtime_error const& e)
01148 {
01149 size_type line = basic_keyfile.get_line(group, key);
01150 if (line)
01151 throw error(line, group, key, PASSTHROUGH_LGK, e);
01152 else
01153 throw error(group, key, PASSTHROUGH_GK, e);
01154 throw error(basic_keyfile.get_line(group, key),
01155 group, key, e);
01156 }
01157 }
01158
01174 template<class C, typename T>
01175 static void
01176 get_object_list_value (C& object,
01177 void (C::* method)(T const& param),
01178 basic_keyfile const& basic_keyfile,
01179 group_name_type const& group,
01180 key_type const& key,
01181 basic_keyfile::priority priority)
01182 {
01183 try
01184 {
01185 T value;
01186 if (basic_keyfile.get_list_value(group, key, priority, value)
01187 && method)
01188 (object.*method)(value);
01189 }
01190 catch (std::runtime_error const& e)
01191 {
01192 size_type line = basic_keyfile.get_line(group, key);
01193 if (line)
01194 throw error(line, group, key, PASSTHROUGH_LGK, e);
01195 else
01196 throw error(group, key, PASSTHROUGH_GK, e);
01197 throw error(basic_keyfile.get_line(group, key),
01198 group, key, e);
01199 }
01200 }
01201 };
01202
01203 }
01204
01205 #include <sbuild/sbuild-basic-keyfile.tcc>
01206
01207 #endif
01208
01209
01210
01211
01212
01213