00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef SBUILD_BASIC_KEYFILE_H
00021 #define SBUILD_BASIC_KEYFILE_H
00022
00023 #include <sbuild/sbuild-i18n.h>
00024 #include <sbuild/sbuild-log.h>
00025 #include <sbuild/sbuild-keyfile-base.h>
00026 #include <sbuild/sbuild-parse-error.h>
00027 #include <sbuild/sbuild-parse-value.h>
00028 #include <sbuild/sbuild-types.h>
00029 #include <sbuild/sbuild-tr1types.h>
00030 #include <sbuild/sbuild-util.h>
00031
00032 #include <cassert>
00033 #include <map>
00034 #include <string>
00035 #include <sstream>
00036
00037 #include <boost/format.hpp>
00038
00039 namespace sbuild
00040 {
00044 template <typename K>
00045 class basic_keyfile_parser
00046 {
00047 public:
00049 typedef keyfile_base::error error;
00050
00052 basic_keyfile_parser ()
00053 {
00054 }
00055
00057 virtual ~basic_keyfile_parser ()
00058 {
00059 }
00060
00062 typename K::group_name_type group;
00063
00065 bool group_set;
00066
00068 typename K::key_type key;
00069
00071 bool key_set;
00072
00074 typename K::value_type value;
00075
00077 bool value_set;
00078
00080 typename K::comment_type comment;
00081
00083 bool comment_set;
00084
00086 typename K::size_type line_number;
00087
00092 virtual void
00093 begin ()
00094 {
00095 line_number = 0;
00096 }
00097
00108 virtual void
00109 parse_line (std::string const& line)
00110 {
00111 ++line_number;
00112 }
00113
00118 virtual void
00119 end()
00120 {
00121 }
00122 };
00123
00130 template <typename K, typename P = basic_keyfile_parser<K> >
00131 class basic_keyfile : public keyfile_base
00132 {
00133 private:
00135 typedef typename K::group_name_type group_name_type;
00136
00138 typedef typename K::key_type key_type;
00139
00141 typedef typename K::value_type value_type;
00142
00144 typedef typename K::comment_type comment_type;
00145
00147 typedef typename K::size_type size_type;
00148
00150 typedef P parse_type;
00151
00153 typedef std::tr1::tuple<key_type,value_type,comment_type,size_type>
00154 item_type;
00155
00157 typedef std::map<key_type,item_type> item_map_type;
00158
00160 typedef std::tr1::tuple<group_name_type,item_map_type,comment_type,size_type> group_type;
00161
00163 typedef std::map<group_name_type,group_type> group_map_type;
00164
00165 public:
00167 basic_keyfile ();
00168
00174 basic_keyfile (std::string const& file);
00175
00181 basic_keyfile (std::istream& stream);
00182
00184 virtual ~basic_keyfile ();
00185
00192 string_list
00193 get_groups () const;
00194
00202 string_list
00203 get_keys (group_name_type const& group) const;
00204
00211 bool
00212 has_group (group_name_type const& group) const;
00213
00221 bool
00222 has_key (group_name_type const& group,
00223 key_type const& key) const;
00224
00232 void
00233 set_group (group_name_type const& group,
00234 comment_type const& comment);
00235
00244 void
00245 set_group (group_name_type const& group,
00246 comment_type const& comment,
00247 size_type line);
00248
00255 comment_type
00256 get_comment (group_name_type const& group) const;
00257
00265 comment_type
00266 get_comment (group_name_type const& group,
00267 key_type const& key) const;
00268
00275 size_type
00276 get_line (group_name_type const& group) const;
00277
00285 size_type
00286 get_line (group_name_type const& group,
00287 key_type const& key) const;
00288
00299 template <typename T>
00300 bool
00301 get_value (group_name_type const& group,
00302 key_type const& key,
00303 T& value) const
00304 {
00305 log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00306 << ", key=" << key << std::endl;
00307 const item_type *found_item = find_item(group, key);
00308 if (found_item)
00309 {
00310 value_type const& strval(std::tr1::get<1>(*found_item));
00311 try
00312 {
00313 parse_value(strval, value);
00314 return true;
00315 }
00316 catch (parse_value_error const& e)
00317 {
00318 size_type line = get_line(group, key);
00319 if (line)
00320 {
00321 error ep(line, group, key, PASSTHROUGH_LGK, e);
00322 log_exception_warning(ep);
00323 }
00324 else
00325 {
00326 error ep(group, key, PASSTHROUGH_GK, e);
00327 log_exception_warning(ep);
00328 }
00329 return false;
00330 }
00331 }
00332 log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00333 return false;
00334 }
00335
00348 template <typename T>
00349 bool
00350 get_value (group_name_type const& group,
00351 key_type const& key,
00352 priority priority,
00353 T& value) const
00354 {
00355 bool status = get_value(group, key, value);
00356 check_priority(group, key, priority, status);
00357 return status;
00358 }
00359
00369 bool
00370 get_locale_string (group_name_type const& group,
00371 key_type const& key,
00372 std::string& value) const;
00373
00385 bool
00386 get_locale_string (group_name_type const& group,
00387 key_type const& key,
00388 priority priority,
00389 std::string& value) const;
00390
00401 bool
00402 get_locale_string (group_name_type const& group,
00403 key_type const& key,
00404 std::string const& locale,
00405 std::string& value) const;
00406
00420 bool
00421 get_locale_string (group_name_type const& group,
00422 key_type const& key,
00423 std::string const& locale,
00424 priority priority,
00425 std::string& value) const;
00426
00439 template <typename C>
00440 bool
00441 get_list_value (group_name_type const& group,
00442 key_type const& key,
00443 C& container) const
00444 {
00445 std::string item_value;
00446 if (get_value(group, key, item_value))
00447 {
00448 string_list items = split_string(item_value,
00449 std::string(1, this->separator));
00450 for (string_list::const_iterator pos = items.begin();
00451 pos != items.end();
00452 ++pos
00453 )
00454 {
00455 typename C::value_type tmp;
00456
00457 try
00458 {
00459 parse_value(*pos, tmp);
00460 }
00461 catch (parse_value_error const& e)
00462 {
00463 size_type line = get_line(group, key);
00464 if (line)
00465 {
00466 error ep(line, group, key, PASSTHROUGH_LGK, e);
00467 log_exception_warning(ep);
00468 }
00469 else
00470 {
00471 error ep(group, key, PASSTHROUGH_GK, e);
00472 log_exception_warning(ep);
00473 }
00474 return false;
00475 }
00476
00477 container.push_back(tmp);
00478 }
00479 return true;
00480 }
00481 return false;
00482 }
00483
00498 template <typename C>
00499 bool
00500 get_list_value (group_name_type const& group,
00501 key_type const& key,
00502 priority priority,
00503 C& container) const
00504 {
00505 bool status = get_list_value(group, key, container);
00506 check_priority(group, key, priority, status);
00507 return status;
00508 }
00509
00518 template <typename T>
00519 void
00520 set_value (group_name_type const& group,
00521 key_type const& key,
00522 T const& value)
00523 {
00524 set_value(group, key, value, comment_type());
00525 }
00526
00536 template <typename T>
00537 void
00538 set_value (group_name_type const& group,
00539 key_type const& key,
00540 T const& value,
00541 comment_type const& comment)
00542 {
00543 set_value(group, key, value, comment, 0);
00544 }
00545
00556 template <typename T>
00557 void
00558 set_value (group_name_type const& group,
00559 key_type const& key,
00560 T const& value,
00561 comment_type const& comment,
00562 size_type line)
00563 {
00564 std::ostringstream os;
00565 os.imbue(std::locale::classic());
00566 os << std::boolalpha << value;
00567
00568 set_group(group, "");
00569 group_type *found_group = find_group(group);
00570 assert (found_group != 0);
00571
00572 item_map_type& items = std::tr1::get<1>(*found_group);
00573
00574 typename item_map_type::iterator pos = items.find(key);
00575 if (pos != items.end())
00576 items.erase(pos);
00577 items.insert
00578 (typename item_map_type::value_type(key,
00579 item_type(key, os.str(), comment, line)));
00580 }
00581
00591 template <typename I>
00592 void
00593 set_list_value (group_name_type const& group,
00594 key_type const& key,
00595 I begin,
00596 I end)
00597 {
00598 set_list_value(group, key, begin, end, comment_type());
00599 }
00600
00611 template <typename I>
00612 void
00613 set_list_value (group_name_type const& group,
00614 key_type const& key,
00615 I begin,
00616 I end,
00617 comment_type const& comment)
00618 {
00619 set_list_value (group, key, begin, end, comment, 0);
00620 }
00621
00633 template <typename I>
00634 void
00635 set_list_value (group_name_type const& group,
00636 key_type const& key,
00637 I begin,
00638 I end,
00639 comment_type const& comment,
00640 size_type line)
00641 {
00642 std::string strval;
00643
00644 for (I pos = begin; pos != end; ++ pos)
00645 {
00646 std::ostringstream os;
00647 os.imbue(std::locale::classic());
00648 os << std::boolalpha << *pos;
00649 if (os)
00650 {
00651 strval += os.str();
00652 if (pos + 1 != end)
00653 strval += this->separator;
00654 }
00655 }
00656
00657 set_value (group, key, strval, comment, line);
00658 }
00659
00665 void
00666 remove_group (group_name_type const& group);
00667
00674 void
00675 remove_key (group_name_type const& group,
00676 key_type const& key);
00677
00684 basic_keyfile&
00685 operator += (basic_keyfile const& rhs);
00686
00694 template <typename _K, typename _P>
00695 friend basic_keyfile<_K, _P>
00696 operator + (basic_keyfile<_K, _P> const& lhs,
00697 basic_keyfile<_K, _P> const& rhs);
00698
00706 template <class charT, class traits>
00707 friend
00708 std::basic_istream<charT,traits>&
00709 operator >> (std::basic_istream<charT,traits>& stream,
00710 basic_keyfile& kf)
00711 {
00712 basic_keyfile tmp;
00713 parse_type state;
00714 std::string line;
00715
00716 state.begin();
00717
00718 while (std::getline(stream, line))
00719 {
00720 state.parse_line(line);
00721
00722
00723 if (state.group_set)
00724 {
00725 if (tmp.has_group(state.group))
00726 throw error(state.line_number, DUPLICATE_GROUP, state.group);
00727 else
00728 tmp.set_group(state.group, state.comment, state.line_number);
00729 }
00730
00731
00732 if (state.key_set && state.value_set)
00733 {
00734 if (tmp.has_key(state.group, state.key))
00735 throw error(state.line_number, state.group, DUPLICATE_KEY, state.key);
00736 else
00737 tmp.set_value(state.group, state.key, state.value, state.comment, state.line_number);
00738 }
00739 }
00740
00741 state.end();
00742
00743
00744 kf += tmp;
00745
00746 return stream;
00747 }
00748
00756 template <class charT, class traits>
00757 friend
00758 std::basic_ostream<charT,traits>&
00759 operator << (std::basic_ostream<charT,traits>& stream,
00760 basic_keyfile const& kf)
00761 {
00762 size_type group_count = 0;
00763
00764 for (typename group_map_type::const_iterator gp = kf.groups.begin();
00765 gp != kf.groups.end();
00766 ++gp, ++group_count)
00767 {
00768 if (group_count > 0)
00769 stream << '\n';
00770
00771 group_type const& group = gp->second;
00772 group_name_type const& groupname = std::tr1::get<0>(group);
00773 comment_type const& comment = std::tr1::get<2>(group);
00774
00775 if (comment.length() > 0)
00776 print_comment(comment, stream);
00777
00778 stream << '[' << groupname << ']' << '\n';
00779
00780 item_map_type const& items(std::tr1::get<1>(group));
00781 for (typename item_map_type::const_iterator it = items.begin();
00782 it != items.end();
00783 ++it)
00784 {
00785 item_type const& item = it->second;
00786 key_type const& key(std::tr1::get<0>(item));
00787 value_type const& value(std::tr1::get<1>(item));
00788 comment_type const& comment(std::tr1::get<2>(item));
00789
00790 if (comment.length() > 0)
00791 print_comment(comment, stream);
00792
00793 stream << key << '=' << value << '\n';
00794 }
00795 }
00796
00797 return stream;
00798 }
00799
00800 private:
00807 const group_type *
00808 find_group (group_name_type const& group) const;
00809
00816 group_type *
00817 find_group (group_name_type const& group);
00818
00826 const item_type *
00827 find_item (group_name_type const& group,
00828 key_type const& key) const;
00829
00837 item_type *
00838 find_item (group_name_type const& group,
00839 key_type const& key);
00840
00849 void
00850 check_priority (group_name_type const& group,
00851 key_type const& key,
00852 priority priority,
00853 bool valid) const;
00854
00866 static void
00867 print_comment (comment_type const& comment,
00868 std::ostream& stream);
00869
00871 group_map_type groups;
00873 char separator;
00874
00875 public:
00888 template<class C, typename T>
00889 static void
00890 set_object_value (C const& object,
00891 T (C::* method)() const,
00892 basic_keyfile& basic_keyfile,
00893 group_name_type const& group,
00894 key_type const& key)
00895 {
00896 try
00897 {
00898 basic_keyfile.set_value(group, key, (object.*method)());
00899 }
00900 catch (std::runtime_error const& e)
00901 {
00902 throw error(group, key, PASSTHROUGH_GK, e);
00903 }
00904 }
00905
00918 template<class C, typename T>
00919 static void
00920 set_object_value (C const& object,
00921 T const& (C::* method)() const,
00922 basic_keyfile& basic_keyfile,
00923 group_name_type const& group,
00924 key_type const& key)
00925 {
00926 try
00927 {
00928 basic_keyfile.set_value(group, key, (object.*method)());
00929 }
00930 catch (std::runtime_error const& e)
00931 {
00932 throw error(group, key, PASSTHROUGH_GK, e);
00933 }
00934 }
00935
00949 template<class C, typename T>
00950 static void
00951 set_object_list_value (C const& object,
00952 T (C::* method)() const,
00953 basic_keyfile& basic_keyfile,
00954 group_name_type const& group,
00955 key_type const& key)
00956 {
00957 try
00958 {
00959 basic_keyfile.set_list_value(group, key,
00960 (object.*method)().begin(),
00961 (object.*method)().end());
00962 }
00963 catch (std::runtime_error const& e)
00964 {
00965 throw error(group, key, PASSTHROUGH_GK, e);
00966 }
00967 }
00968
00983 template<class C, typename T>
00984 static void
00985 set_object_list_value (C const& object,
00986 T const& (C::* method)() const,
00987 basic_keyfile& basic_keyfile,
00988 group_name_type const& group,
00989 key_type const& key)
00990 {
00991 try
00992 {
00993 basic_keyfile.set_list_value(group, key,
00994 (object.*method)().begin(),
00995 (object.*method)().end());
00996 }
00997 catch (std::runtime_error const& e)
00998 {
00999 throw error(group, key, PASSTHROUGH_GK, e);
01000 }
01001 }
01002
01017 template<class C, typename T>
01018 static void
01019 get_object_value (C& object,
01020 void (C::* method)(T param),
01021 basic_keyfile const& basic_keyfile,
01022 group_name_type const& group,
01023 key_type const& key,
01024 basic_keyfile::priority priority)
01025 {
01026 try
01027 {
01028 T value;
01029 if (basic_keyfile.get_value(group, key, priority, value))
01030 (object.*method)(value);
01031 }
01032 catch (std::runtime_error const& e)
01033 {
01034 size_type line = basic_keyfile.get_line(group, key);
01035 if (line)
01036 throw error(line, group, key, PASSTHROUGH_LGK, e);
01037 else
01038 throw error(group, key, PASSTHROUGH_GK, e);
01039 }
01040 }
01041
01056 template<class C, typename T>
01057 static void
01058 get_object_value (C& object,
01059 void (C::* method)(T const& param),
01060 basic_keyfile const& basic_keyfile,
01061 group_name_type const& group,
01062 key_type const& key,
01063 basic_keyfile::priority priority)
01064 {
01065 try
01066 {
01067 T value;
01068 if (basic_keyfile.get_value(group, key, priority, value))
01069 (object.*method)(value);
01070 }
01071 catch (std::runtime_error const& e)
01072 {
01073 size_type line = basic_keyfile.get_line(group, key);
01074 if (line)
01075 throw error(line, group, key, PASSTHROUGH_LGK, e);
01076 else
01077 throw error(group, key, PASSTHROUGH_GK, e);
01078 }
01079 }
01080
01095 template<class C, typename T>
01096 static void
01097 get_object_list_value (C& object,
01098 void (C::* method)(T param),
01099 basic_keyfile const& basic_keyfile,
01100 group_name_type const& group,
01101 key_type const& key,
01102 basic_keyfile::priority priority)
01103 {
01104 try
01105 {
01106 T value;
01107 if (basic_keyfile.get_list_value(group, key, priority, value))
01108 (object.*method)(value);
01109 }
01110 catch (std::runtime_error const& e)
01111 {
01112 size_type line = basic_keyfile.get_line(group, key);
01113 if (line)
01114 throw error(line, group, key, PASSTHROUGH_LGK, e);
01115 else
01116 throw error(group, key, PASSTHROUGH_GK, e);
01117 throw error(basic_keyfile.get_line(group, key),
01118 group, key, e);
01119 }
01120 }
01121
01137 template<class C, typename T>
01138 static void
01139 get_object_list_value (C& object,
01140 void (C::* method)(T const& param),
01141 basic_keyfile const& basic_keyfile,
01142 group_name_type const& group,
01143 key_type const& key,
01144 basic_keyfile::priority priority)
01145 {
01146 try
01147 {
01148 T value;
01149 if (basic_keyfile.get_list_value(group, key, priority, value))
01150 (object.*method)(value);
01151 }
01152 catch (std::runtime_error const& e)
01153 {
01154 size_type line = basic_keyfile.get_line(group, key);
01155 if (line)
01156 throw error(line, group, key, PASSTHROUGH_LGK, e);
01157 else
01158 throw error(group, key, PASSTHROUGH_GK, e);
01159 throw error(basic_keyfile.get_line(group, key),
01160 group, key, e);
01161 }
01162 }
01163 };
01164
01165 }
01166
01167 #include <sbuild/sbuild-basic-keyfile.tcc>
01168
01169 #endif
01170
01171
01172
01173
01174
01175