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::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::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::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
00551 template <typename C>
00552 bool
00553 get_set_value (group_name_type const& group,
00554 key_type const& key,
00555 C& container) const
00556 {
00557 value_type item_value;
00558 if (get_value(group, key, item_value))
00559 {
00560 value_list items = split_string(item_value,
00561 this->separator);
00562 for (typename value_list::const_iterator pos = items.begin();
00563 pos != items.end();
00564 ++pos
00565 )
00566 {
00567 typename C::value_type tmp;
00568
00569 try
00570 {
00571 parse_value(*pos, tmp);
00572 }
00573 catch (parse_value_error const& e)
00574 {
00575 size_type line = get_line(group, key);
00576 if (line)
00577 {
00578 error ep(line, group, key, PASSTHROUGH_LGK, e);
00579 log_exception_warning(ep);
00580 }
00581 else
00582 {
00583 error ep(group, key, PASSTHROUGH_GK, e);
00584 log_exception_warning(ep);
00585 }
00586 return false;
00587 }
00588
00589 container.insert(tmp);
00590 }
00591 return true;
00592 }
00593 return false;
00594 }
00595
00610 template <typename C>
00611 bool
00612 get_set_value (group_name_type const& group,
00613 key_type const& key,
00614 priority priority,
00615 C& container) const
00616 {
00617 bool status = get_set_value(group, key, container);
00618 check_priority(group, key, priority, status);
00619 return status;
00620 }
00621
00630 template <typename T>
00631 void
00632 set_value (group_name_type const& group,
00633 key_type const& key,
00634 T const& value)
00635 {
00636 set_value(group, key, value, comment_type());
00637 }
00638
00648 template <typename T>
00649 void
00650 set_value (group_name_type const& group,
00651 key_type const& key,
00652 T const& value,
00653 comment_type const& comment)
00654 {
00655 set_value(group, key, value, comment, 0);
00656 }
00657
00668 template <typename T>
00669 void
00670 set_value (group_name_type const& group,
00671 key_type const& key,
00672 T const& value,
00673 comment_type const& comment,
00674 size_type line)
00675 {
00676 std::ostringstream os;
00677 os.imbue(std::locale::classic());
00678 os << std::boolalpha << value;
00679
00680 set_group(group, "");
00681 group_type *found_group = find_group(group);
00682 assert (found_group != 0);
00683
00684 item_map_type& items = std::get<1>(*found_group);
00685
00686 typename item_map_type::iterator pos = items.find(key);
00687 if (pos != items.end())
00688 items.erase(pos);
00689 items.insert
00690 (typename item_map_type::value_type(key,
00691 item_type(key, os.str(),
00692 comment, line)));
00693 }
00694
00704 template <typename I>
00705 void
00706 set_list_value (group_name_type const& group,
00707 key_type const& key,
00708 I begin,
00709 I end)
00710 {
00711 set_list_value(group, key, begin, end, comment_type());
00712 }
00713
00724 template <typename I>
00725 void
00726 set_list_value (group_name_type const& group,
00727 key_type const& key,
00728 I begin,
00729 I end,
00730 comment_type const& comment)
00731 {
00732 set_list_value (group, key, begin, end, comment, 0);
00733 }
00734
00746 template <typename I>
00747 void
00748 set_list_value (group_name_type const& group,
00749 key_type const& key,
00750 I begin,
00751 I end,
00752 comment_type const& comment,
00753 size_type line)
00754 {
00755 value_type strval;
00756
00757 for (I pos = begin; pos != end;)
00758 {
00759 std::ostringstream os;
00760 os.imbue(std::locale::classic());
00761 os << std::boolalpha << *pos;
00762 if (os)
00763 {
00764 strval += os.str();
00765 if (++pos != end)
00766 strval += this->separator;
00767 }
00768 }
00769
00770 set_value (group, key, strval, comment, line);
00771 }
00772
00782 template <typename I>
00783 void
00784 set_set_value (group_name_type const& group,
00785 key_type const& key,
00786 I begin,
00787 I end)
00788 {
00789 std::vector<typename std::iterator_traits<I>::value_type> l(begin, end);
00790 std::sort(l.begin(), l.end());
00791 set_list_value(group, key, l.begin(), l.end());
00792 }
00793
00804 template <typename I>
00805 void
00806 set_set_value (group_name_type const& group,
00807 key_type const& key,
00808 I begin,
00809 I end,
00810 comment_type const& comment)
00811 {
00812 std::vector<typename std::iterator_traits<I>::value_type> l(begin, end);
00813 std::sort(l.begin(), l.end());
00814 set_list_value(group, key, l.begin(), l.end(), comment);
00815 }
00816
00828 template <typename I>
00829 void
00830 set_set_value (group_name_type const& group,
00831 key_type const& key,
00832 I begin,
00833 I end,
00834 comment_type const& comment,
00835 size_type line)
00836 {
00837 std::vector<typename std::iterator_traits<I>::value_type> l(begin, end);
00838 std::sort(l.begin(), l.end());
00839 set_list_value(group, key, l.begin(), l.end(), comment, line);
00840 }
00841
00847 void
00848 remove_group (group_name_type const& group);
00849
00856 void
00857 remove_key (group_name_type const& group,
00858 key_type const& key);
00859
00866 basic_keyfile&
00867 operator += (basic_keyfile const& rhs);
00868
00876 template <typename _K, typename _P>
00877 friend basic_keyfile<_K, _P>
00878 operator + (basic_keyfile<_K, _P> const& lhs,
00879 basic_keyfile<_K, _P> const& rhs);
00880
00888 template <class charT, class traits>
00889 friend
00890 std::basic_istream<charT,traits>&
00891 operator >> (std::basic_istream<charT,traits>& stream,
00892 basic_keyfile& kf)
00893 {
00894 basic_keyfile tmp;
00895 parse_type state;
00896 std::string line;
00897
00898 state.begin();
00899
00900 while (std::getline(stream, line))
00901 {
00902 state.parse_line(line);
00903
00904
00905 if (state.group_set)
00906 {
00907 if (tmp.has_group(state.group))
00908 throw error(state.line_number, DUPLICATE_GROUP, state.group);
00909 else
00910 tmp.set_group(state.group, state.comment, state.line_number);
00911 }
00912
00913
00914 if (state.key_set && state.value_set)
00915 {
00916 if (tmp.has_key(state.group, state.key))
00917 throw error(state.line_number, state.group, DUPLICATE_KEY, state.key);
00918 else
00919 tmp.set_value(state.group, state.key, state.value, state.comment, state.line_number);
00920 }
00921 }
00922
00923 state.end();
00924
00925
00926 kf += tmp;
00927
00928 return stream;
00929 }
00930
00938 template <class charT, class traits>
00939 friend
00940 std::basic_ostream<charT,traits>&
00941 operator << (std::basic_ostream<charT,traits>& stream,
00942 basic_keyfile const& kf)
00943 {
00944 size_type group_count = 0;
00945
00946 for (typename group_map_type::const_iterator gp = kf.groups.begin();
00947 gp != kf.groups.end();
00948 ++gp, ++group_count)
00949 {
00950 if (group_count > 0)
00951 stream << '\n';
00952
00953 group_type const& group = gp->second;
00954 group_name_type const& groupname = std::get<0>(group);
00955 comment_type const& comment = std::get<2>(group);
00956
00957 if (comment.length() > 0)
00958 print_comment(comment, stream);
00959
00960 stream << '[' << groupname << ']' << '\n';
00961
00962 item_map_type const& items(std::get<1>(group));
00963 for (typename item_map_type::const_iterator it = items.begin();
00964 it != items.end();
00965 ++it)
00966 {
00967 item_type const& item = it->second;
00968 key_type const& key(std::get<0>(item));
00969 value_type const& value(std::get<1>(item));
00970 comment_type const& comment(std::get<2>(item));
00971
00972 if (comment.length() > 0)
00973 print_comment(comment, stream);
00974
00975 stream << key << '=' << value << '\n';
00976 }
00977 }
00978
00979 return stream;
00980 }
00981
00982 private:
00989 const group_type *
00990 find_group (group_name_type const& group) const;
00991
00998 group_type *
00999 find_group (group_name_type const& group);
01000
01008 const item_type *
01009 find_item (group_name_type const& group,
01010 key_type const& key) const;
01011
01019 item_type *
01020 find_item (group_name_type const& group,
01021 key_type const& key);
01022
01031 void
01032 check_priority (group_name_type const& group,
01033 key_type const& key,
01034 priority priority,
01035 bool valid) const;
01036
01048 static void
01049 print_comment (comment_type const& comment,
01050 std::ostream& stream);
01051
01053 group_map_type groups;
01055 value_type separator;
01056
01057 public:
01070 template<class C, typename T>
01071 static void
01072 set_object_value (C const& object,
01073 T (C::* method)() const,
01074 basic_keyfile& basic_keyfile,
01075 group_name_type const& group,
01076 key_type const& key)
01077 {
01078 try
01079 {
01080 if (method)
01081 basic_keyfile.set_value(group, key, (object.*method)());
01082 }
01083 catch (std::runtime_error const& e)
01084 {
01085 throw error(group, key, PASSTHROUGH_GK, e);
01086 }
01087 }
01088
01101 template<class C, typename T>
01102 static void
01103 set_object_value (C const& object,
01104 T const& (C::* method)() const,
01105 basic_keyfile& basic_keyfile,
01106 group_name_type const& group,
01107 key_type const& key)
01108 {
01109 try
01110 {
01111 if (method)
01112 basic_keyfile.set_value(group, key, (object.*method)());
01113 }
01114 catch (std::runtime_error const& e)
01115 {
01116 throw error(group, key, PASSTHROUGH_GK, e);
01117 }
01118 }
01119
01133 template<class C, typename T>
01134 static void
01135 set_object_list_value (C const& object,
01136 T (C::* method)() const,
01137 basic_keyfile& basic_keyfile,
01138 group_name_type const& group,
01139 key_type const& key)
01140 {
01141 try
01142 {
01143 if (method)
01144 basic_keyfile.set_list_value(group, key,
01145 (object.*method)().begin(),
01146 (object.*method)().end());
01147 }
01148 catch (std::runtime_error const& e)
01149 {
01150 throw error(group, key, PASSTHROUGH_GK, e);
01151 }
01152 }
01153
01168 template<class C, typename T>
01169 static void
01170 set_object_list_value (C const& object,
01171 T const& (C::* method)() const,
01172 basic_keyfile& basic_keyfile,
01173 group_name_type const& group,
01174 key_type const& key)
01175 {
01176 try
01177 {
01178 if (method)
01179 basic_keyfile.set_list_value(group, key,
01180 (object.*method)().begin(),
01181 (object.*method)().end());
01182 }
01183 catch (std::runtime_error const& e)
01184 {
01185 throw error(group, key, PASSTHROUGH_GK, e);
01186 }
01187 }
01188
01202 template<class C, typename T>
01203 static void
01204 set_object_set_value (C const& object,
01205 T (C::* method)() const,
01206 basic_keyfile& basic_keyfile,
01207 group_name_type const& group,
01208 key_type const& key)
01209 {
01210 try
01211 {
01212 if (method)
01213 basic_keyfile.set_set_value(group, key,
01214 (object.*method)().begin(),
01215 (object.*method)().end());
01216 }
01217 catch (std::runtime_error const& e)
01218 {
01219 throw error(group, key, PASSTHROUGH_GK, e);
01220 }
01221 }
01222
01237 template<class C, typename T>
01238 static void
01239 set_object_set_value (C const& object,
01240 T const& (C::* method)() const,
01241 basic_keyfile& basic_keyfile,
01242 group_name_type const& group,
01243 key_type const& key)
01244 {
01245 try
01246 {
01247 if (method)
01248 basic_keyfile.set_set_value(group, key,
01249 (object.*method)().begin(),
01250 (object.*method)().end());
01251 }
01252 catch (std::runtime_error const& e)
01253 {
01254 throw error(group, key, PASSTHROUGH_GK, e);
01255 }
01256 }
01257
01272 template<class C, typename T>
01273 static void
01274 get_object_value (C& object,
01275 void (C::* method)(T param),
01276 basic_keyfile const& basic_keyfile,
01277 group_name_type const& group,
01278 key_type const& key,
01279 basic_keyfile::priority priority)
01280 {
01281 try
01282 {
01283 T value;
01284 if (basic_keyfile.get_value(group, key, priority, value)
01285 && method)
01286 (object.*method)(value);
01287 }
01288 catch (std::runtime_error const& e)
01289 {
01290 size_type line = basic_keyfile.get_line(group, key);
01291 if (line)
01292 throw error(line, group, key, PASSTHROUGH_LGK, e);
01293 else
01294 throw error(group, key, PASSTHROUGH_GK, e);
01295 }
01296 }
01297
01312 template<class C, typename T>
01313 static void
01314 get_object_value (C& object,
01315 void (C::* method)(T const& param),
01316 basic_keyfile const& basic_keyfile,
01317 group_name_type const& group,
01318 key_type const& key,
01319 basic_keyfile::priority priority)
01320 {
01321 try
01322 {
01323 T value;
01324 if (basic_keyfile.get_value(group, key, priority, value)
01325 && method)
01326 (object.*method)(value);
01327 }
01328 catch (std::runtime_error const& e)
01329 {
01330 size_type line = basic_keyfile.get_line(group, key);
01331 if (line)
01332 throw error(line, group, key, PASSTHROUGH_LGK, e);
01333 else
01334 throw error(group, key, PASSTHROUGH_GK, e);
01335 }
01336 }
01337
01352 template<class C, typename T>
01353 static void
01354 get_object_list_value (C& object,
01355 void (C::* method)(T param),
01356 basic_keyfile const& basic_keyfile,
01357 group_name_type const& group,
01358 key_type const& key,
01359 basic_keyfile::priority priority)
01360 {
01361 try
01362 {
01363 T value;
01364 if (basic_keyfile.get_list_value(group, key, priority, value)
01365 && method)
01366 (object.*method)(value);
01367 }
01368 catch (std::runtime_error const& e)
01369 {
01370 size_type line = basic_keyfile.get_line(group, key);
01371 if (line)
01372 throw error(line, group, key, PASSTHROUGH_LGK, e);
01373 else
01374 throw error(group, key, PASSTHROUGH_GK, e);
01375 throw error(basic_keyfile.get_line(group, key),
01376 group, key, e);
01377 }
01378 }
01379
01395 template<class C, typename T>
01396 static void
01397 get_object_list_value (C& object,
01398 void (C::* method)(T const& param),
01399 basic_keyfile const& basic_keyfile,
01400 group_name_type const& group,
01401 key_type const& key,
01402 basic_keyfile::priority priority)
01403 {
01404 try
01405 {
01406 T value;
01407 if (basic_keyfile.get_list_value(group, key, priority, value)
01408 && method)
01409 (object.*method)(value);
01410 }
01411 catch (std::runtime_error const& e)
01412 {
01413 size_type line = basic_keyfile.get_line(group, key);
01414 if (line)
01415 throw error(line, group, key, PASSTHROUGH_LGK, e);
01416 else
01417 throw error(group, key, PASSTHROUGH_GK, e);
01418 throw error(basic_keyfile.get_line(group, key),
01419 group, key, e);
01420 }
01421 }
01422
01437 template<class C, typename T>
01438 static void
01439 get_object_set_value (C& object,
01440 void (C::* method)(T param),
01441 basic_keyfile const& basic_keyfile,
01442 group_name_type const& group,
01443 key_type const& key,
01444 basic_keyfile::priority priority)
01445 {
01446 try
01447 {
01448 T value;
01449 if (basic_keyfile.get_set_value(group, key, priority, value)
01450 && method)
01451 (object.*method)(value);
01452 }
01453 catch (std::runtime_error const& e)
01454 {
01455 size_type line = basic_keyfile.get_line(group, key);
01456 if (line)
01457 throw error(line, group, key, PASSTHROUGH_LGK, e);
01458 else
01459 throw error(group, key, PASSTHROUGH_GK, e);
01460 throw error(basic_keyfile.get_line(group, key),
01461 group, key, e);
01462 }
01463 }
01464
01480 template<class C, typename T>
01481 static void
01482 get_object_set_value (C& object,
01483 void (C::* method)(T const& param),
01484 basic_keyfile const& basic_keyfile,
01485 group_name_type const& group,
01486 key_type const& key,
01487 basic_keyfile::priority priority)
01488 {
01489 try
01490 {
01491 T value;
01492 if (basic_keyfile.get_set_value(group, key, priority, value)
01493 && method)
01494 (object.*method)(value);
01495 }
01496 catch (std::runtime_error const& e)
01497 {
01498 size_type line = basic_keyfile.get_line(group, key);
01499 if (line)
01500 throw error(line, group, key, PASSTHROUGH_LGK, e);
01501 else
01502 throw error(group, key, PASSTHROUGH_GK, e);
01503 throw error(basic_keyfile.get_line(group, key),
01504 group, key, e);
01505 }
01506 }
01507 };
01508
01509 }
01510
01511 #include <sbuild/sbuild-basic-keyfile.tcc>
01512
01513 #endif
01514
01515
01516
01517
01518
01519