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 {
00053 }
00054
00056 virtual ~basic_keyfile_parser ()
00057 {
00058 }
00059
00061 typename K::group_name_type group;
00062
00064 bool group_set;
00065
00067 typename K::key_type key;
00068
00070 bool key_set;
00071
00073 typename K::value_type value;
00074
00076 bool value_set;
00077
00079 typename K::comment_type comment;
00080
00082 bool comment_set;
00083
00085 typename K::size_type line_number;
00086
00091 virtual void
00092 begin ()
00093 {
00094 line_number = 0;
00095 }
00096
00107 virtual void
00108 parse_line (std::string const& line)
00109 {
00110 ++line_number;
00111 }
00112
00117 virtual void
00118 end()
00119 {
00120 }
00121 };
00122
00129 template <typename K, typename P = basic_keyfile_parser<K> >
00130 class basic_keyfile : public keyfile_base
00131 {
00132 public:
00134 typedef typename K::group_name_type group_name_type;
00135
00137 typedef typename K::key_type key_type;
00138
00140 typedef typename K::value_type value_type;
00141
00143 typedef typename K::comment_type comment_type;
00144
00146 typedef typename K::size_type size_type;
00147
00148 private:
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
00213 void
00214 check_keys (group_name_type const& group,
00215 string_list const& keys) const;
00216
00223 bool
00224 has_group (group_name_type const& group) const;
00225
00233 bool
00234 has_key (group_name_type const& group,
00235 key_type const& key) const;
00236
00244 void
00245 set_group (group_name_type const& group,
00246 comment_type const& comment);
00247
00256 void
00257 set_group (group_name_type const& group,
00258 comment_type const& comment,
00259 size_type line);
00260
00267 comment_type
00268 get_comment (group_name_type const& group) const;
00269
00277 comment_type
00278 get_comment (group_name_type const& group,
00279 key_type const& key) const;
00280
00287 size_type
00288 get_line (group_name_type const& group) const;
00289
00297 size_type
00298 get_line (group_name_type const& group,
00299 key_type const& key) const;
00300
00311 template <typename T>
00312 bool
00313 get_value (group_name_type const& group,
00314 key_type const& key,
00315 T& value) const
00316 {
00317 log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00318 << ", key=" << key << std::endl;
00319 const item_type *found_item = find_item(group, key);
00320 if (found_item)
00321 {
00322 value_type const& strval(std::tr1::get<1>(*found_item));
00323 try
00324 {
00325 parse_value(strval, value);
00326 return true;
00327 }
00328 catch (parse_value_error const& e)
00329 {
00330 size_type line = get_line(group, key);
00331 if (line)
00332 {
00333 error ep(line, group, key, PASSTHROUGH_LGK, e);
00334 log_exception_warning(ep);
00335 }
00336 else
00337 {
00338 error ep(group, key, PASSTHROUGH_GK, e);
00339 log_exception_warning(ep);
00340 }
00341 return false;
00342 }
00343 }
00344 log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00345 return false;
00346 }
00347
00360 template <typename T>
00361 bool
00362 get_value (group_name_type const& group,
00363 key_type const& key,
00364 priority priority,
00365 T& value) const
00366 {
00367 bool status = get_value(group, key, value);
00368 check_priority(group, key, priority, status);
00369 return status;
00370 }
00371
00381 bool
00382 get_locale_string (group_name_type const& group,
00383 key_type const& key,
00384 std::string& value) const;
00385
00397 bool
00398 get_locale_string (group_name_type const& group,
00399 key_type const& key,
00400 priority priority,
00401 std::string& value) const;
00402
00413 bool
00414 get_locale_string (group_name_type const& group,
00415 key_type const& key,
00416 std::string const& locale,
00417 std::string& value) const;
00418
00432 bool
00433 get_locale_string (group_name_type const& group,
00434 key_type const& key,
00435 std::string const& locale,
00436 priority priority,
00437 std::string& value) const;
00438
00451 template <typename C>
00452 bool
00453 get_list_value (group_name_type const& group,
00454 key_type const& key,
00455 C& container) const
00456 {
00457 std::string item_value;
00458 if (get_value(group, key, item_value))
00459 {
00460 string_list items = split_string(item_value,
00461 std::string(1, this->separator));
00462 for (string_list::const_iterator pos = items.begin();
00463 pos != items.end();
00464 ++pos
00465 )
00466 {
00467 typename C::value_type tmp;
00468
00469 try
00470 {
00471 parse_value(*pos, tmp);
00472 }
00473 catch (parse_value_error const& e)
00474 {
00475 size_type line = get_line(group, key);
00476 if (line)
00477 {
00478 error ep(line, group, key, PASSTHROUGH_LGK, e);
00479 log_exception_warning(ep);
00480 }
00481 else
00482 {
00483 error ep(group, key, PASSTHROUGH_GK, e);
00484 log_exception_warning(ep);
00485 }
00486 return false;
00487 }
00488
00489 container.push_back(tmp);
00490 }
00491 return true;
00492 }
00493 return false;
00494 }
00495
00510 template <typename C>
00511 bool
00512 get_list_value (group_name_type const& group,
00513 key_type const& key,
00514 priority priority,
00515 C& container) const
00516 {
00517 bool status = get_list_value(group, key, container);
00518 check_priority(group, key, priority, status);
00519 return status;
00520 }
00521
00530 template <typename T>
00531 void
00532 set_value (group_name_type const& group,
00533 key_type const& key,
00534 T const& value)
00535 {
00536 set_value(group, key, value, comment_type());
00537 }
00538
00548 template <typename T>
00549 void
00550 set_value (group_name_type const& group,
00551 key_type const& key,
00552 T const& value,
00553 comment_type const& comment)
00554 {
00555 set_value(group, key, value, comment, 0);
00556 }
00557
00568 template <typename T>
00569 void
00570 set_value (group_name_type const& group,
00571 key_type const& key,
00572 T const& value,
00573 comment_type const& comment,
00574 size_type line)
00575 {
00576 std::ostringstream os;
00577 os.imbue(std::locale::classic());
00578 os << std::boolalpha << value;
00579
00580 set_group(group, "");
00581 group_type *found_group = find_group(group);
00582 assert (found_group != 0);
00583
00584 item_map_type& items = std::tr1::get<1>(*found_group);
00585
00586 typename item_map_type::iterator pos = items.find(key);
00587 if (pos != items.end())
00588 items.erase(pos);
00589 items.insert
00590 (typename item_map_type::value_type(key,
00591 item_type(key, os.str(), comment, line)));
00592 }
00593
00603 template <typename I>
00604 void
00605 set_list_value (group_name_type const& group,
00606 key_type const& key,
00607 I begin,
00608 I end)
00609 {
00610 set_list_value(group, key, begin, end, comment_type());
00611 }
00612
00623 template <typename I>
00624 void
00625 set_list_value (group_name_type const& group,
00626 key_type const& key,
00627 I begin,
00628 I end,
00629 comment_type const& comment)
00630 {
00631 set_list_value (group, key, begin, end, comment, 0);
00632 }
00633
00645 template <typename I>
00646 void
00647 set_list_value (group_name_type const& group,
00648 key_type const& key,
00649 I begin,
00650 I end,
00651 comment_type const& comment,
00652 size_type line)
00653 {
00654 std::string strval;
00655
00656 for (I pos = begin; pos != end; ++ pos)
00657 {
00658 std::ostringstream os;
00659 os.imbue(std::locale::classic());
00660 os << std::boolalpha << *pos;
00661 if (os)
00662 {
00663 strval += os.str();
00664 if (pos + 1 != end)
00665 strval += this->separator;
00666 }
00667 }
00668
00669 set_value (group, key, strval, comment, line);
00670 }
00671
00677 void
00678 remove_group (group_name_type const& group);
00679
00686 void
00687 remove_key (group_name_type const& group,
00688 key_type const& key);
00689
00696 basic_keyfile&
00697 operator += (basic_keyfile const& rhs);
00698
00706 template <typename _K, typename _P>
00707 friend basic_keyfile<_K, _P>
00708 operator + (basic_keyfile<_K, _P> const& lhs,
00709 basic_keyfile<_K, _P> const& rhs);
00710
00718 template <class charT, class traits>
00719 friend
00720 std::basic_istream<charT,traits>&
00721 operator >> (std::basic_istream<charT,traits>& stream,
00722 basic_keyfile& kf)
00723 {
00724 basic_keyfile tmp;
00725 parse_type state;
00726 std::string line;
00727
00728 state.begin();
00729
00730 while (std::getline(stream, line))
00731 {
00732 state.parse_line(line);
00733
00734
00735 if (state.group_set)
00736 {
00737 if (tmp.has_group(state.group))
00738 throw error(state.line_number, DUPLICATE_GROUP, state.group);
00739 else
00740 tmp.set_group(state.group, state.comment, state.line_number);
00741 }
00742
00743
00744 if (state.key_set && state.value_set)
00745 {
00746 if (tmp.has_key(state.group, state.key))
00747 throw error(state.line_number, state.group, DUPLICATE_KEY, state.key);
00748 else
00749 tmp.set_value(state.group, state.key, state.value, state.comment, state.line_number);
00750 }
00751 }
00752
00753 state.end();
00754
00755
00756 kf += tmp;
00757
00758 return stream;
00759 }
00760
00768 template <class charT, class traits>
00769 friend
00770 std::basic_ostream<charT,traits>&
00771 operator << (std::basic_ostream<charT,traits>& stream,
00772 basic_keyfile const& kf)
00773 {
00774 size_type group_count = 0;
00775
00776 for (typename group_map_type::const_iterator gp = kf.groups.begin();
00777 gp != kf.groups.end();
00778 ++gp, ++group_count)
00779 {
00780 if (group_count > 0)
00781 stream << '\n';
00782
00783 group_type const& group = gp->second;
00784 group_name_type const& groupname = std::tr1::get<0>(group);
00785 comment_type const& comment = std::tr1::get<2>(group);
00786
00787 if (comment.length() > 0)
00788 print_comment(comment, stream);
00789
00790 stream << '[' << groupname << ']' << '\n';
00791
00792 item_map_type const& items(std::tr1::get<1>(group));
00793 for (typename item_map_type::const_iterator it = items.begin();
00794 it != items.end();
00795 ++it)
00796 {
00797 item_type const& item = it->second;
00798 key_type const& key(std::tr1::get<0>(item));
00799 value_type const& value(std::tr1::get<1>(item));
00800 comment_type const& comment(std::tr1::get<2>(item));
00801
00802 if (comment.length() > 0)
00803 print_comment(comment, stream);
00804
00805 stream << key << '=' << value << '\n';
00806 }
00807 }
00808
00809 return stream;
00810 }
00811
00812 private:
00819 const group_type *
00820 find_group (group_name_type const& group) const;
00821
00828 group_type *
00829 find_group (group_name_type const& group);
00830
00838 const item_type *
00839 find_item (group_name_type const& group,
00840 key_type const& key) const;
00841
00849 item_type *
00850 find_item (group_name_type const& group,
00851 key_type const& key);
00852
00861 void
00862 check_priority (group_name_type const& group,
00863 key_type const& key,
00864 priority priority,
00865 bool valid) const;
00866
00878 static void
00879 print_comment (comment_type const& comment,
00880 std::ostream& stream);
00881
00883 group_map_type groups;
00885 char separator;
00886
00887 public:
00900 template<class C, typename T>
00901 static void
00902 set_object_value (C const& object,
00903 T (C::* method)() const,
00904 basic_keyfile& basic_keyfile,
00905 group_name_type const& group,
00906 key_type const& key)
00907 {
00908 try
00909 {
00910 basic_keyfile.set_value(group, key, (object.*method)());
00911 }
00912 catch (std::runtime_error const& e)
00913 {
00914 throw error(group, key, PASSTHROUGH_GK, e);
00915 }
00916 }
00917
00930 template<class C, typename T>
00931 static void
00932 set_object_value (C const& object,
00933 T const& (C::* method)() const,
00934 basic_keyfile& basic_keyfile,
00935 group_name_type const& group,
00936 key_type const& key)
00937 {
00938 try
00939 {
00940 basic_keyfile.set_value(group, key, (object.*method)());
00941 }
00942 catch (std::runtime_error const& e)
00943 {
00944 throw error(group, key, PASSTHROUGH_GK, e);
00945 }
00946 }
00947
00961 template<class C, typename T>
00962 static void
00963 set_object_list_value (C const& object,
00964 T (C::* method)() const,
00965 basic_keyfile& basic_keyfile,
00966 group_name_type const& group,
00967 key_type const& key)
00968 {
00969 try
00970 {
00971 basic_keyfile.set_list_value(group, key,
00972 (object.*method)().begin(),
00973 (object.*method)().end());
00974 }
00975 catch (std::runtime_error const& e)
00976 {
00977 throw error(group, key, PASSTHROUGH_GK, e);
00978 }
00979 }
00980
00995 template<class C, typename T>
00996 static void
00997 set_object_list_value (C const& object,
00998 T const& (C::* method)() const,
00999 basic_keyfile& basic_keyfile,
01000 group_name_type const& group,
01001 key_type const& key)
01002 {
01003 try
01004 {
01005 basic_keyfile.set_list_value(group, key,
01006 (object.*method)().begin(),
01007 (object.*method)().end());
01008 }
01009 catch (std::runtime_error const& e)
01010 {
01011 throw error(group, key, PASSTHROUGH_GK, e);
01012 }
01013 }
01014
01029 template<class C, typename T>
01030 static void
01031 get_object_value (C& object,
01032 void (C::* method)(T param),
01033 basic_keyfile const& basic_keyfile,
01034 group_name_type const& group,
01035 key_type const& key,
01036 basic_keyfile::priority priority)
01037 {
01038 try
01039 {
01040 T value;
01041 if (basic_keyfile.get_value(group, key, priority, value))
01042 (object.*method)(value);
01043 }
01044 catch (std::runtime_error const& e)
01045 {
01046 size_type line = basic_keyfile.get_line(group, key);
01047 if (line)
01048 throw error(line, group, key, PASSTHROUGH_LGK, e);
01049 else
01050 throw error(group, key, PASSTHROUGH_GK, e);
01051 }
01052 }
01053
01068 template<class C, typename T>
01069 static void
01070 get_object_value (C& object,
01071 void (C::* method)(T const& param),
01072 basic_keyfile const& basic_keyfile,
01073 group_name_type const& group,
01074 key_type const& key,
01075 basic_keyfile::priority priority)
01076 {
01077 try
01078 {
01079 T value;
01080 if (basic_keyfile.get_value(group, key, priority, value))
01081 (object.*method)(value);
01082 }
01083 catch (std::runtime_error const& e)
01084 {
01085 size_type line = basic_keyfile.get_line(group, key);
01086 if (line)
01087 throw error(line, group, key, PASSTHROUGH_LGK, e);
01088 else
01089 throw error(group, key, PASSTHROUGH_GK, e);
01090 }
01091 }
01092
01107 template<class C, typename T>
01108 static void
01109 get_object_list_value (C& object,
01110 void (C::* method)(T param),
01111 basic_keyfile const& basic_keyfile,
01112 group_name_type const& group,
01113 key_type const& key,
01114 basic_keyfile::priority priority)
01115 {
01116 try
01117 {
01118 T value;
01119 if (basic_keyfile.get_list_value(group, key, priority, value))
01120 (object.*method)(value);
01121 }
01122 catch (std::runtime_error const& e)
01123 {
01124 size_type line = basic_keyfile.get_line(group, key);
01125 if (line)
01126 throw error(line, group, key, PASSTHROUGH_LGK, e);
01127 else
01128 throw error(group, key, PASSTHROUGH_GK, e);
01129 throw error(basic_keyfile.get_line(group, key),
01130 group, key, e);
01131 }
01132 }
01133
01149 template<class C, typename T>
01150 static void
01151 get_object_list_value (C& object,
01152 void (C::* method)(T const& param),
01153 basic_keyfile const& basic_keyfile,
01154 group_name_type const& group,
01155 key_type const& key,
01156 basic_keyfile::priority priority)
01157 {
01158 try
01159 {
01160 T value;
01161 if (basic_keyfile.get_list_value(group, key, priority, value))
01162 (object.*method)(value);
01163 }
01164 catch (std::runtime_error const& e)
01165 {
01166 size_type line = basic_keyfile.get_line(group, key);
01167 if (line)
01168 throw error(line, group, key, PASSTHROUGH_LGK, e);
01169 else
01170 throw error(group, key, PASSTHROUGH_GK, e);
01171 throw error(basic_keyfile.get_line(group, key),
01172 group, key, e);
01173 }
01174 }
01175 };
01176
01177 }
01178
01179 #include <sbuild/sbuild-basic-keyfile.tcc>
01180
01181 #endif
01182
01183
01184
01185
01186
01187