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> item_type;
00052
00054 typedef std::map<std::string,item_type> item_map_type;
00055
00057 typedef std::tr1::tuple<std::string,item_map_type,std::string> group_type;
00058
00060 typedef std::map<std::string,group_type> group_map_type;
00061
00062 public:
00064 enum priority
00065 {
00066 PRIORITY_OPTIONAL,
00067 PRIORITY_REQUIRED,
00068 PRIORITY_DISALLOWED,
00069 PRIORITY_DEPRECATED,
00070 PRIORITY_OBSOLETE
00071 };
00072
00074 typedef parse_error error;
00075
00077 keyfile ();
00078
00084 keyfile (std::string const& file);
00085
00091 keyfile (std::istream& stream);
00092
00094 virtual ~keyfile ();
00095
00102 string_list
00103 get_groups () const;
00104
00112 string_list
00113 get_keys (std::string const& group) const;
00114
00121 bool
00122 has_group (std::string const& group) const;
00123
00131 bool
00132 has_key (std::string const& group,
00133 std::string const& key) const;
00134
00142 void
00143 set_group (std::string const& group,
00144 std::string const& comment);
00145
00152 std::string
00153 get_comment (std::string const& group) const;
00154
00162 std::string
00163 get_comment (std::string const& group,
00164 std::string const& key) const;
00165
00176 template <typename T>
00177 bool
00178 get_value (std::string const& group,
00179 std::string const& key,
00180 T& value) const
00181 {
00182 log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00183 << ", key=" << key << std::endl;
00184 const item_type *found_item = find_item(group, key);
00185 if (found_item)
00186 {
00187 std::string const& strval(std::tr1::get<1>(*found_item));
00188 try
00189 {
00190 value = static_cast<T const&>(parse_value(strval));
00191 return true;
00192 }
00193 catch (parse_value::error const& e)
00194 {
00195 error ep(group, key, parse_error::NONE, e.what());
00196 log_warning() << ep.what() << std::endl;
00197 return false;
00198 }
00199 }
00200 log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00201 return false;
00202 }
00203
00216 template <typename T>
00217 bool
00218 get_value (std::string const& group,
00219 std::string const& key,
00220 priority priority,
00221 T& value) const
00222 {
00223 bool status = get_value(group, key, value);
00224 check_priority(group, key, priority, status);
00225 return status;
00226 }
00227
00237 bool
00238 get_locale_string (std::string const& group,
00239 std::string const& key,
00240 std::string& value) const;
00241
00253 bool
00254 get_locale_string (std::string const& group,
00255 std::string const& key,
00256 priority priority,
00257 std::string& value) const;
00258
00269 bool
00270 get_locale_string (std::string const& group,
00271 std::string const& key,
00272 std::string const& locale,
00273 std::string& value) const;
00274
00288 bool
00289 get_locale_string (std::string const& group,
00290 std::string const& key,
00291 std::string const& locale,
00292 priority priority,
00293 std::string& value) const;
00294
00307 template <typename C>
00308 bool
00309 get_list_value (std::string const& group,
00310 std::string const& key,
00311 C& container) const
00312 {
00313 std::string item_value;
00314 if (get_value(group, key, item_value))
00315 {
00316 string_list items = split_string(item_value,
00317 std::string(1, this->separator));
00318 for (string_list::const_iterator pos = items.begin();
00319 pos != items.end();
00320 ++pos
00321 )
00322 {
00323 container.push_back(static_cast<typename C::const_reference>(parse_value(*pos)));
00324 }
00325 return true;
00326 }
00327 return false;
00328 }
00329
00344 template <typename C>
00345 bool
00346 get_list_value (std::string const& group,
00347 std::string const& key,
00348 priority priority,
00349 C& container) const
00350 {
00351 bool status = get_list_value(group, key, container);
00352 check_priority(group, key, priority, status);
00353 return status;
00354 }
00355
00364 template <typename T>
00365 void
00366 set_value (std::string const& group,
00367 std::string const& key,
00368 T const& value)
00369 {
00370 set_value(group, key, value, std::string());
00371 }
00372
00382 template <typename T>
00383 void
00384 set_value (std::string const& group,
00385 std::string const& key,
00386 T const& value,
00387 std::string const& comment)
00388 {
00389 std::ostringstream os;
00390 os.imbue(std::locale("C"));
00391 os << std::boolalpha << value;
00392
00393 set_group(group, "");
00394 group_type *found_group = find_group(group);
00395 assert (found_group != 0);
00396
00397 item_map_type& items = std::tr1::get<1>(*found_group);
00398
00399 item_map_type::iterator pos = items.find(key);
00400 if (pos != items.end())
00401 items.erase(pos);
00402
00403 items.insert
00404 (item_map_type::value_type(key,
00405 item_type(key, os.str(), comment)));
00406 }
00407
00417 template <typename I>
00418 void
00419 set_list_value (std::string const& group,
00420 std::string const& key,
00421 I begin,
00422 I end)
00423 {
00424 set_list_value(group, key, begin, end, std::string());
00425 }
00426
00437 template <typename I>
00438 void
00439 set_list_value (std::string const& group,
00440 std::string const& key,
00441 I begin,
00442 I end,
00443 std::string const& comment)
00444 {
00445 std::string strval;
00446
00447 for (I pos = begin; pos != end; ++ pos)
00448 {
00449 std::ostringstream os;
00450 os.imbue(std::locale("C"));
00451 os << std::boolalpha << *pos;
00452 if (os)
00453 {
00454 strval += os.str();
00455 if (pos + 1 != end)
00456 strval += this->separator;
00457 }
00458 }
00459
00460 set_value (group, key, strval, comment);
00461 }
00462
00468 void
00469 remove_group (std::string const& group);
00470
00477 void
00478 remove_key (std::string const& group,
00479 std::string const& key);
00480
00487 keyfile&
00488 operator += (keyfile const& rhs);
00489
00497 friend keyfile
00498 operator + (keyfile const& lhs,
00499 keyfile const& rhs);
00500
00504 template <class charT, class traits>
00505 friend
00506 std::basic_istream<charT,traits>&
00507 operator >> (std::basic_istream<charT,traits>& stream,
00508 keyfile& kf)
00509 {
00510 keyfile tmp;
00511 size_t linecount = 0;
00512 std::string line;
00513 std::string group;
00514 std::string comment;
00515 std::string key;
00516 std::string value;
00517
00518 while (std::getline(stream, line))
00519 {
00520 linecount++;
00521
00522 if (line.length() == 0)
00523 {
00524
00525 }
00526 else if (line[0] == '#')
00527 {
00528 if (!comment.empty())
00529 comment += '\n';
00530 comment += line.substr(1);
00531 }
00532 else if (line[0] == '[')
00533 {
00534 std::string::size_type fpos = line.find_first_of(']');
00535 std::string::size_type lpos = line.find_last_of(']');
00536 if (fpos == std::string::npos || lpos == std::string::npos ||
00537 fpos != lpos)
00538 {
00539 throw error(linecount, parse_error::INVALID_GROUP, line);
00540 }
00541 group = line.substr(1, fpos - 1);
00542
00543 if (group.length() == 0)
00544 {
00545 throw error(linecount, parse_error::INVALID_GROUP, line);
00546 }
00547
00548
00549 if (tmp.has_group(group))
00550 {
00551 error e(linecount, parse_error::DUPLICATE_GROUP, group);
00552 log_warning() << e.what() << std::endl;
00553 }
00554 else
00555 tmp.set_group(group, comment);
00556 comment.clear();
00557 }
00558 else
00559 {
00560 std::string::size_type pos = line.find_first_of('=');
00561 if (pos == std::string::npos)
00562 {
00563 throw error(linecount, parse_error::INVALID_LINE, line);
00564 }
00565 if (pos == 0)
00566 {
00567 throw error(linecount, parse_error::NO_KEY, line);
00568 }
00569 key = line.substr(0, pos);
00570 if (pos == line.length() - 1)
00571 value = "";
00572 else
00573 value = line.substr(pos + 1);
00574
00575
00576 if (group.empty())
00577 {
00578 throw error(linecount, parse_error::NO_GROUP, line);
00579 }
00580
00581
00582 if (tmp.has_key(group, key))
00583 {
00584 error e(linecount, group, parse_error::DUPLICATE_KEY, key);
00585 log_warning() << e.what() << std::endl;
00586 }
00587 else
00588 tmp.set_value(group, key, value, comment);
00589 comment.clear();
00590 }
00591 }
00592
00593 kf += tmp;
00594
00595 return stream;
00596 }
00597
00601 template <class charT, class traits>
00602 friend
00603 std::basic_ostream<charT,traits>&
00604 operator << (std::basic_ostream<charT,traits>& stream,
00605 keyfile const& kf)
00606 {
00607 unsigned int group_count = 0;
00608
00609 for (group_map_type::const_iterator gp = kf.groups.begin();
00610 gp != kf.groups.end();
00611 ++gp, ++group_count)
00612 {
00613 if (group_count > 0)
00614 stream << '\n';
00615
00616 group_type const& group = gp->second;
00617 std::string const& groupname = std::tr1::get<0>(group);
00618 std::string const& comment = std::tr1::get<2>(group);
00619
00620 if (comment.length() > 0)
00621 print_comment(comment, stream);
00622
00623 stream << '[' << groupname << ']' << '\n';
00624
00625 item_map_type const& items(std::tr1::get<1>(group));
00626 for (item_map_type::const_iterator it = items.begin();
00627 it != items.end();
00628 ++it)
00629 {
00630 item_type const& item = it->second;
00631 std::string const& key(std::tr1::get<0>(item));
00632 std::string const& value(std::tr1::get<1>(item));
00633 std::string const& comment(std::tr1::get<2>(item));
00634
00635 if (comment.length() > 0)
00636 print_comment(comment, stream);
00637
00638 stream << key << '=' << value << '\n';
00639 }
00640 }
00641
00642 return stream;
00643 }
00644
00645 private:
00652 const group_type *
00653 find_group (std::string const& group) const;
00654
00661 group_type *
00662 find_group (std::string const& group);
00663
00671 const item_type *
00672 find_item (std::string const& group,
00673 std::string const& key) const;
00674
00682 item_type *
00683 find_item (std::string const& group,
00684 std::string const& key);
00685
00694 void
00695 check_priority (std::string const& group,
00696 std::string const& key,
00697 priority priority,
00698 bool valid) const;
00699
00707 static void
00708 print_comment (std::string const& comment,
00709 std::ostream& stream);
00710
00712 group_map_type groups;
00714 char separator;
00715 };
00716
00717 }
00718
00719 #endif
00720
00721
00722
00723
00724
00725