sbuild 1.4.23
|
00001 /* Copyright © 2005-2009 Roger Leigh <rleigh@debian.org> 00002 * 00003 * schroot is free software: you can redistribute it and/or modify it 00004 * under the terms of the GNU General Public License as published by 00005 * the Free Software Foundation, either version 3 of the License, or 00006 * (at your option) any later version. 00007 * 00008 * schroot is distributed in the hope that it will be useful, but 00009 * WITHOUT ANY WARRANTY; without even the implied warranty of 00010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 * General Public License for more details. 00012 * 00013 * You should have received a copy of the GNU General Public License 00014 * along with this program. If not, see 00015 * <http://www.gnu.org/licenses/>. 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); // should not fail 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 // Insert group 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 // Insert item 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 // TODO: do inserts here as well. 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 /* SBUILD_BASIC_KEYFILE_H */ 01208 01209 /* 01210 * Local Variables: 01211 * mode:C++ 01212 * End: 01213 */