00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef SBUILD_KEYFILE_H
00021 #define SBUILD_KEYFILE_H
00022
00023 #include <sbuild/sbuild-i18n.h>
00024 #include <sbuild/sbuild-log.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 {
00040
00047 class keyfile
00048 {
00049 private:
00051 typedef std::tr1::tuple<std::string,std::string,std::string,unsigned int>
00052 item_type;
00053
00055 typedef std::map<std::string,item_type> item_map_type;
00056
00058 typedef std::tr1::tuple<std::string,item_map_type,std::string,unsigned int> group_type;
00059
00061 typedef std::map<std::string,group_type> group_map_type;
00062
00063 public:
00065 enum priority
00066 {
00067 PRIORITY_OPTIONAL,
00068 PRIORITY_REQUIRED,
00069 PRIORITY_DISALLOWED,
00070 PRIORITY_DEPRECATED,
00071 PRIORITY_OBSOLETE
00072 };
00073
00075 enum error_code
00076 {
00077 BAD_FILE,
00078 DEPRECATED_KEY,
00079 DEPRECATED_KEY_NL,
00080 DISALLOWED_KEY,
00081 DISALLOWED_KEY_NL,
00082 DUPLICATE_GROUP,
00083 DUPLICATE_KEY,
00084 INVALID_GROUP,
00085 INVALID_LINE,
00086 MISSING_KEY,
00087 MISSING_KEY_NL,
00088 NO_GROUP,
00089 NO_KEY,
00090 OBSOLETE_KEY,
00091 OBSOLETE_KEY_NL,
00092 PASSTHROUGH_G,
00093 PASSTHROUGH_GK,
00094 PASSTHROUGH_LG,
00095 PASSTHROUGH_LGK
00096 };
00097
00099 typedef parse_error<error_code> error;
00100
00102 keyfile ();
00103
00109 keyfile (std::string const& file);
00110
00116 keyfile (std::istream& stream);
00117
00119 virtual ~keyfile ();
00120
00127 string_list
00128 get_groups () const;
00129
00137 string_list
00138 get_keys (std::string const& group) const;
00139
00146 bool
00147 has_group (std::string const& group) const;
00148
00156 bool
00157 has_key (std::string const& group,
00158 std::string const& key) const;
00159
00167 void
00168 set_group (std::string const& group,
00169 std::string const& comment);
00170
00179 void
00180 set_group (std::string const& group,
00181 std::string const& comment,
00182 unsigned int line);
00183
00190 std::string
00191 get_comment (std::string const& group) const;
00192
00200 std::string
00201 get_comment (std::string const& group,
00202 std::string const& key) const;
00203
00210 unsigned int
00211 get_line (std::string const& group) const;
00212
00220 unsigned int
00221 get_line (std::string const& group,
00222 std::string const& key) const;
00223
00234 template <typename T>
00235 bool
00236 get_value (std::string const& group,
00237 std::string const& key,
00238 T& value) const
00239 {
00240 log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00241 << ", key=" << key << std::endl;
00242 const item_type *found_item = find_item(group, key);
00243 if (found_item)
00244 {
00245 std::string const& strval(std::tr1::get<1>(*found_item));
00246 try
00247 {
00248 parse_value(strval, value);
00249 return true;
00250 }
00251 catch (parse_value_error const& e)
00252 {
00253 unsigned int line = get_line(group, key);
00254 if (line)
00255 {
00256 error ep(line, group, key, PASSTHROUGH_LGK, e);
00257 log_exception_warning(ep);
00258 }
00259 else
00260 {
00261 error ep(group, key, PASSTHROUGH_GK, e);
00262 log_exception_warning(ep);
00263 }
00264 return false;
00265 }
00266 }
00267 log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00268 return false;
00269 }
00270
00283 template <typename T>
00284 bool
00285 get_value (std::string const& group,
00286 std::string const& key,
00287 priority priority,
00288 T& value) const
00289 {
00290 bool status = get_value(group, key, value);
00291 check_priority(group, key, priority, status);
00292 return status;
00293 }
00294
00304 bool
00305 get_locale_string (std::string const& group,
00306 std::string const& key,
00307 std::string& value) const;
00308
00320 bool
00321 get_locale_string (std::string const& group,
00322 std::string const& key,
00323 priority priority,
00324 std::string& value) const;
00325
00336 bool
00337 get_locale_string (std::string const& group,
00338 std::string const& key,
00339 std::string const& locale,
00340 std::string& value) const;
00341
00355 bool
00356 get_locale_string (std::string const& group,
00357 std::string const& key,
00358 std::string const& locale,
00359 priority priority,
00360 std::string& value) const;
00361
00374 template <typename C>
00375 bool
00376 get_list_value (std::string const& group,
00377 std::string const& key,
00378 C& container) const
00379 {
00380 std::string item_value;
00381 if (get_value(group, key, item_value))
00382 {
00383 string_list items = split_string(item_value,
00384 std::string(1, this->separator));
00385 for (string_list::const_iterator pos = items.begin();
00386 pos != items.end();
00387 ++pos
00388 )
00389 {
00390 typename C::value_type tmp;
00391
00392 try
00393 {
00394 parse_value(*pos, tmp);
00395 }
00396 catch (parse_value_error const& e)
00397 {
00398 unsigned int line = get_line(group, key);
00399 if (line)
00400 {
00401 error ep(line, group, key, PASSTHROUGH_LGK, e);
00402 log_exception_warning(ep);
00403 }
00404 else
00405 {
00406 error ep(group, key, PASSTHROUGH_GK, e);
00407 log_exception_warning(ep);
00408 }
00409 return false;
00410 }
00411
00412 container.push_back(tmp);
00413 }
00414 return true;
00415 }
00416 return false;
00417 }
00418
00433 template <typename C>
00434 bool
00435 get_list_value (std::string const& group,
00436 std::string const& key,
00437 priority priority,
00438 C& container) const
00439 {
00440 bool status = get_list_value(group, key, container);
00441 check_priority(group, key, priority, status);
00442 return status;
00443 }
00444
00453 template <typename T>
00454 void
00455 set_value (std::string const& group,
00456 std::string const& key,
00457 T const& value)
00458 {
00459 set_value(group, key, value, std::string());
00460 }
00461
00471 template <typename T>
00472 void
00473 set_value (std::string const& group,
00474 std::string const& key,
00475 T const& value,
00476 std::string const& comment)
00477 {
00478 set_value(group, key, value, comment, 0);
00479 }
00480
00491 template <typename T>
00492 void
00493 set_value (std::string const& group,
00494 std::string const& key,
00495 T const& value,
00496 std::string const& comment,
00497 unsigned int line)
00498 {
00499 std::ostringstream os;
00500 os.imbue(std::locale::classic());
00501 os << std::boolalpha << value;
00502
00503 set_group(group, "");
00504 group_type *found_group = find_group(group);
00505 assert (found_group != 0);
00506
00507 item_map_type& items = std::tr1::get<1>(*found_group);
00508
00509 item_map_type::iterator pos = items.find(key);
00510 if (pos != items.end())
00511 items.erase(pos);
00512 items.insert
00513 (item_map_type::value_type(key,
00514 item_type(key, os.str(), comment, line)));
00515 }
00516
00526 template <typename I>
00527 void
00528 set_list_value (std::string const& group,
00529 std::string const& key,
00530 I begin,
00531 I end)
00532 {
00533 set_list_value(group, key, begin, end, std::string());
00534 }
00535
00546 template <typename I>
00547 void
00548 set_list_value (std::string const& group,
00549 std::string const& key,
00550 I begin,
00551 I end,
00552 std::string const& comment)
00553 {
00554 set_list_value (group, key, begin, end, comment, 0);
00555 }
00556
00568 template <typename I>
00569 void
00570 set_list_value (std::string const& group,
00571 std::string const& key,
00572 I begin,
00573 I end,
00574 std::string const& comment,
00575 unsigned int line)
00576 {
00577 std::string strval;
00578
00579 for (I pos = begin; pos != end; ++ pos)
00580 {
00581 std::ostringstream os;
00582 os.imbue(std::locale::classic());
00583 os << std::boolalpha << *pos;
00584 if (os)
00585 {
00586 strval += os.str();
00587 if (pos + 1 != end)
00588 strval += this->separator;
00589 }
00590 }
00591
00592 set_value (group, key, strval, comment, line);
00593 }
00594
00600 void
00601 remove_group (std::string const& group);
00602
00609 void
00610 remove_key (std::string const& group,
00611 std::string const& key);
00612
00619 keyfile&
00620 operator += (keyfile const& rhs);
00621
00629 friend keyfile
00630 operator + (keyfile const& lhs,
00631 keyfile const& rhs);
00632
00640 template <class charT, class traits>
00641 friend
00642 std::basic_istream<charT,traits>&
00643 operator >> (std::basic_istream<charT,traits>& stream,
00644 keyfile& kf)
00645 {
00646 keyfile tmp;
00647 size_t linecount = 0;
00648 std::string line;
00649 std::string group;
00650 std::string comment;
00651 std::string key;
00652 std::string value;
00653
00654 while (std::getline(stream, line))
00655 {
00656 linecount++;
00657
00658 if (line.length() == 0)
00659 {
00660
00661 }
00662 else if (line[0] == '#')
00663 {
00664 if (!comment.empty())
00665 comment += '\n';
00666 comment += line.substr(1);
00667 }
00668 else if (line[0] == '[')
00669 {
00670 std::string::size_type fpos = line.find_first_of(']');
00671 std::string::size_type lpos = line.find_last_of(']');
00672 if (fpos == std::string::npos || lpos == std::string::npos ||
00673 fpos != lpos)
00674 throw error(linecount, INVALID_GROUP, line);
00675 group = line.substr(1, fpos - 1);
00676
00677 if (group.length() == 0)
00678 throw error(linecount, INVALID_GROUP, line);
00679
00680
00681 if (tmp.has_group(group))
00682 throw error(linecount, DUPLICATE_GROUP, group);
00683 else
00684 tmp.set_group(group, comment, linecount);
00685 comment.clear();
00686 }
00687 else
00688 {
00689 std::string::size_type pos = line.find_first_of('=');
00690 if (pos == std::string::npos)
00691 throw error(linecount, INVALID_LINE, line);
00692 if (pos == 0)
00693 throw error(linecount, NO_KEY, line);
00694 key = line.substr(0, pos);
00695 if (pos == line.length() - 1)
00696 value = "";
00697 else
00698 value = line.substr(pos + 1);
00699
00700
00701 if (group.empty())
00702 throw error(linecount, NO_GROUP, line);
00703
00704
00705 if (tmp.has_key(group, key))
00706 throw error(linecount, group, DUPLICATE_KEY, key);
00707 else
00708 tmp.set_value(group, key, value, comment, linecount);
00709 comment.clear();
00710 }
00711 }
00712
00713 kf += tmp;
00714
00715 return stream;
00716 }
00717
00725 template <class charT, class traits>
00726 friend
00727 std::basic_ostream<charT,traits>&
00728 operator << (std::basic_ostream<charT,traits>& stream,
00729 keyfile const& kf)
00730 {
00731 unsigned int group_count = 0;
00732
00733 for (group_map_type::const_iterator gp = kf.groups.begin();
00734 gp != kf.groups.end();
00735 ++gp, ++group_count)
00736 {
00737 if (group_count > 0)
00738 stream << '\n';
00739
00740 group_type const& group = gp->second;
00741 std::string const& groupname = std::tr1::get<0>(group);
00742 std::string const& comment = std::tr1::get<2>(group);
00743
00744 if (comment.length() > 0)
00745 print_comment(comment, stream);
00746
00747 stream << '[' << groupname << ']' << '\n';
00748
00749 item_map_type const& items(std::tr1::get<1>(group));
00750 for (item_map_type::const_iterator it = items.begin();
00751 it != items.end();
00752 ++it)
00753 {
00754 item_type const& item = it->second;
00755 std::string const& key(std::tr1::get<0>(item));
00756 std::string const& value(std::tr1::get<1>(item));
00757 std::string const& comment(std::tr1::get<2>(item));
00758
00759 if (comment.length() > 0)
00760 print_comment(comment, stream);
00761
00762 stream << key << '=' << value << '\n';
00763 }
00764 }
00765
00766 return stream;
00767 }
00768
00769 private:
00776 const group_type *
00777 find_group (std::string const& group) const;
00778
00785 group_type *
00786 find_group (std::string const& group);
00787
00795 const item_type *
00796 find_item (std::string const& group,
00797 std::string const& key) const;
00798
00806 item_type *
00807 find_item (std::string const& group,
00808 std::string const& key);
00809
00818 void
00819 check_priority (std::string const& group,
00820 std::string const& key,
00821 priority priority,
00822 bool valid) const;
00823
00835 static void
00836 print_comment (std::string const& comment,
00837 std::ostream& stream);
00838
00840 group_map_type groups;
00842 char separator;
00843
00844 public:
00857 template<class C, typename T>
00858 static void
00859 set_object_value (C const& object,
00860 T (C::* method)() const,
00861 keyfile& keyfile,
00862 std::string const& group,
00863 std::string const& key)
00864 {
00865 try
00866 {
00867 keyfile.set_value(group, key, (object.*method)());
00868 }
00869 catch (std::runtime_error const& e)
00870 {
00871 throw error(group, key, PASSTHROUGH_GK, e);
00872 }
00873 }
00874
00887 template<class C, typename T>
00888 static void
00889 set_object_value (C const& object,
00890 T const& (C::* method)() const,
00891 keyfile& keyfile,
00892 std::string const& group,
00893 std::string const& key)
00894 {
00895 try
00896 {
00897 keyfile.set_value(group, key, (object.*method)());
00898 }
00899 catch (std::runtime_error const& e)
00900 {
00901 throw error(group, key, PASSTHROUGH_GK, e);
00902 }
00903 }
00904
00918 template<class C, typename T>
00919 static void
00920 set_object_list_value (C const& object,
00921 T (C::* method)() const,
00922 keyfile& keyfile,
00923 std::string const& group,
00924 std::string const& key)
00925 {
00926 try
00927 {
00928 keyfile.set_list_value(group, key,
00929 (object.*method)().begin(),
00930 (object.*method)().end());
00931 }
00932 catch (std::runtime_error const& e)
00933 {
00934 throw error(group, key, PASSTHROUGH_GK, e);
00935 }
00936 }
00937
00952 template<class C, typename T>
00953 static void
00954 set_object_list_value (C const& object,
00955 T const& (C::* method)() const,
00956 keyfile& keyfile,
00957 std::string const& group,
00958 std::string const& key)
00959 {
00960 try
00961 {
00962 keyfile.set_list_value(group, key,
00963 (object.*method)().begin(),
00964 (object.*method)().end());
00965 }
00966 catch (std::runtime_error const& e)
00967 {
00968 throw error(group, key, PASSTHROUGH_GK, e);
00969 }
00970 }
00971
00986 template<class C, typename T>
00987 static void
00988 get_object_value (C& object,
00989 void (C::* method)(T param),
00990 keyfile const& keyfile,
00991 std::string const& group,
00992 std::string const& key,
00993 keyfile::priority priority)
00994 {
00995 try
00996 {
00997 T value;
00998 if (keyfile.get_value(group, key, priority, value))
00999 (object.*method)(value);
01000 }
01001 catch (std::runtime_error const& e)
01002 {
01003 unsigned int line = keyfile.get_line(group, key);
01004 if (line)
01005 throw error(line, group, key, PASSTHROUGH_LGK, e);
01006 else
01007 throw error(group, key, PASSTHROUGH_GK, e);
01008 }
01009 }
01010
01025 template<class C, typename T>
01026 static void
01027 get_object_value (C& object,
01028 void (C::* method)(T const& param),
01029 keyfile const& keyfile,
01030 std::string const& group,
01031 std::string const& key,
01032 keyfile::priority priority)
01033 {
01034 try
01035 {
01036 T value;
01037 if (keyfile.get_value(group, key, priority, value))
01038 (object.*method)(value);
01039 }
01040 catch (std::runtime_error const& e)
01041 {
01042 unsigned int line = keyfile.get_line(group, key);
01043 if (line)
01044 throw error(line, group, key, PASSTHROUGH_LGK, e);
01045 else
01046 throw error(group, key, PASSTHROUGH_GK, e);
01047 }
01048 }
01049
01064 template<class C, typename T>
01065 static void
01066 get_object_list_value (C& object,
01067 void (C::* method)(T param),
01068 keyfile const& keyfile,
01069 std::string const& group,
01070 std::string const& key,
01071 keyfile::priority priority)
01072 {
01073 try
01074 {
01075 T value;
01076 if (keyfile.get_list_value(group, key, priority, value))
01077 (object.*method)(value);
01078 }
01079 catch (std::runtime_error const& e)
01080 {
01081 unsigned int line = keyfile.get_line(group, key);
01082 if (line)
01083 throw error(line, group, key, PASSTHROUGH_LGK, e);
01084 else
01085 throw error(group, key, PASSTHROUGH_GK, e);
01086 throw error(keyfile.get_line(group, key),
01087 group, key, e);
01088 }
01089 }
01090
01106 template<class C, typename T>
01107 static void
01108 get_object_list_value (C& object,
01109 void (C::* method)(T const& param),
01110 keyfile const& keyfile,
01111 std::string const& group,
01112 std::string const& key,
01113 keyfile::priority priority)
01114 {
01115 try
01116 {
01117 T value;
01118 if (keyfile.get_list_value(group, key, priority, value))
01119 (object.*method)(value);
01120 }
01121 catch (std::runtime_error const& e)
01122 {
01123 unsigned int line = keyfile.get_line(group, key);
01124 if (line)
01125 throw error(line, group, key, PASSTHROUGH_LGK, e);
01126 else
01127 throw error(group, key, PASSTHROUGH_GK, e);
01128 throw error(keyfile.get_line(group, key),
01129 group, key, e);
01130 }
01131 }
01132 };
01133
01134 }
01135
01136 #endif
01137
01138
01139
01140
01141
01142