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-config.h"
00024
00025 #include <cassert>
00026 #include <iostream>
00027 #include <map>
00028 #include <string>
00029 #include <sstream>
00030
00031 #ifdef HAVE_TR1_TUPLE
00032 #include <tr1/tuple>
00033 #elif HAVE_BOOST_TUPLE_TUPLE_HPP
00034 #include <boost/tuple/tuple.hpp>
00035 namespace std { namespace tr1 { using boost::tuple; using boost::get; } }
00036 #else
00037 #error A shared_ptr implementation is not available
00038 #endif
00039
00040 #include <boost/format.hpp>
00041
00042 #include "sbuild-error.h"
00043 #include "sbuild-i18n.h"
00044 #include "sbuild-log.h"
00045 #include "sbuild-parse-error.h"
00046 #include "sbuild-parse-value.h"
00047 #include "sbuild-types.h"
00048 #include "sbuild-util.h"
00049
00050 namespace sbuild
00051 {
00052
00059 class keyfile
00060 {
00061 private:
00063 typedef std::tr1::tuple<std::string,std::string,std::string> item_type;
00064
00066 typedef std::map<std::string,item_type> item_map_type;
00067
00069 typedef std::tr1::tuple<std::string,item_map_type,std::string> group_type;
00070
00072 typedef std::map<std::string,group_type> group_map_type;
00073
00074 public:
00076 enum priority
00077 {
00078 PRIORITY_OPTIONAL,
00079 PRIORITY_REQUIRED,
00080 PRIORITY_DISALLOWED,
00081 PRIORITY_DEPRECATED,
00082 PRIORITY_OBSOLETE
00083 };
00084
00086 typedef parse_error error;
00087
00089 keyfile ();
00090
00096 keyfile (std::string const& file);
00097
00103 keyfile (std::istream& stream);
00104
00106 virtual ~keyfile ();
00107
00114 string_list
00115 get_groups () const;
00116
00124 string_list
00125 get_keys (std::string const& group) const;
00126
00133 bool
00134 has_group (std::string const& group) const;
00135
00143 bool
00144 has_key (std::string const& group,
00145 std::string const& key) const;
00146
00154 void
00155 set_group (std::string const& group,
00156 std::string const& comment);
00157
00164 std::string
00165 get_comment (std::string const& group) const;
00166
00174 std::string
00175 get_comment (std::string const& group,
00176 std::string const& key) const;
00177
00188 template <typename T>
00189 bool
00190 get_value (std::string const& group,
00191 std::string const& key,
00192 T& value) const
00193 {
00194 log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00195 << ", key=" << key << std::endl;
00196 const item_type *found_item = find_item(group, key);
00197 if (found_item)
00198 {
00199 std::string const& strval(std::tr1::get<1>(*found_item));
00200 try
00201 {
00202 value = static_cast<T const&>(parse_value(strval));
00203 return true;
00204 }
00205 catch (parse_value::error const& e)
00206 {
00207 error ep(group, key, parse_error::NONE, e.what());
00208 log_warning() << ep.what() << std::endl;
00209 return false;
00210 }
00211 }
00212 log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00213 return false;
00214 }
00215
00228 template <typename T>
00229 bool
00230 get_value (std::string const& group,
00231 std::string const& key,
00232 priority priority,
00233 T& value) const
00234 {
00235 bool status = get_value(group, key, value);
00236 check_priority(group, key, priority, status);
00237 return status;
00238 }
00239
00249 bool
00250 get_locale_string (std::string const& group,
00251 std::string const& key,
00252 std::string& value) const;
00253
00265 bool
00266 get_locale_string (std::string const& group,
00267 std::string const& key,
00268 priority priority,
00269 std::string& value) const;
00270
00281 bool
00282 get_locale_string (std::string const& group,
00283 std::string const& key,
00284 std::string const& locale,
00285 std::string& value) const;
00286
00300 bool
00301 get_locale_string (std::string const& group,
00302 std::string const& key,
00303 std::string const& locale,
00304 priority priority,
00305 std::string& value) const;
00306
00319 template <typename C>
00320 bool
00321 get_list_value (std::string const& group,
00322 std::string const& key,
00323 C& container) const
00324 {
00325 std::string item_value;
00326 if (get_value(group, key, item_value))
00327 {
00328 string_list items = split_string(item_value, this->separator);
00329 for (string_list::const_iterator pos = items.begin();
00330 pos != items.end();
00331 ++pos
00332 )
00333 {
00334 container.push_back(static_cast<typename C::const_reference>(parse_value(*pos)));
00335
00336 }
00337 return true;
00338 }
00339 return false;
00340 }
00341
00356 template <typename C>
00357 bool
00358 get_list_value (std::string const& group,
00359 std::string const& key,
00360 priority priority,
00361 C& container) const
00362 {
00363 bool status = get_list_value(group, key, container);
00364 check_priority(group, key, priority, status);
00365 return status;
00366 }
00367
00376 template <typename T>
00377 void
00378 set_value (std::string const& group,
00379 std::string const& key,
00380 T const& value)
00381 {
00382 set_value(group, key, value, std::string());
00383 }
00384
00394 template <typename T>
00395 void
00396 set_value (std::string const& group,
00397 std::string const& key,
00398 T const& value,
00399 std::string const& comment)
00400 {
00401 std::ostringstream os;
00402 os.imbue(std::locale("C"));
00403 os << std::boolalpha << value;
00404
00405 set_group(group, "");
00406 group_type *found_group = find_group(group);
00407 assert (found_group != 0);
00408
00409 item_map_type& items = std::tr1::get<1>(*found_group);
00410
00411 item_map_type::iterator pos = items.find(key);
00412 if (pos != items.end())
00413 items.erase(pos);
00414
00415 items.insert
00416 (item_map_type::value_type(key,
00417 item_type(key, os.str(), comment)));
00418 }
00419
00429 template <typename I>
00430 void
00431 set_list_value (std::string const& group,
00432 std::string const& key,
00433 I begin,
00434 I end)
00435 {
00436 set_list_value(group, key, begin, end, std::string());
00437 }
00438
00449 template <typename I>
00450 void
00451 set_list_value (std::string const& group,
00452 std::string const& key,
00453 I begin,
00454 I end,
00455 std::string const& comment)
00456 {
00457 std::string strval;
00458
00459 for (I pos = begin; pos != end; ++ pos)
00460 {
00461 std::ostringstream os;
00462 os.imbue(std::locale("C"));
00463 os << std::boolalpha << *pos;
00464 if (os)
00465 {
00466 strval += os.str();
00467 if (pos + 1 != end)
00468 strval += this->separator;
00469 }
00470 }
00471
00472 set_value (group, key, strval, comment);
00473 }
00474
00480 void
00481 remove_group (std::string const& group);
00482
00489 void
00490 remove_key (std::string const& group,
00491 std::string const& key);
00492
00499 keyfile&
00500 operator += (keyfile const& rhs);
00501
00509 friend keyfile
00510 operator + (keyfile const& lhs,
00511 keyfile const& rhs);
00512
00516 template <class charT, class traits>
00517 friend
00518 std::basic_istream<charT,traits>&
00519 operator >> (std::basic_istream<charT,traits>& stream,
00520 keyfile& kf)
00521 {
00522 keyfile tmp;
00523 size_t linecount = 0;
00524 std::string line;
00525 std::string group;
00526 std::string comment;
00527 std::string key;
00528 std::string value;
00529
00530 while (std::getline(stream, line))
00531 {
00532 linecount++;
00533
00534 if (line.length() == 0)
00535 {
00536
00537 }
00538 else if (line[0] == '#')
00539 {
00540 if (!comment.empty())
00541 comment += '\n';
00542 comment += line.substr(1);
00543 }
00544 else if (line[0] == '[')
00545 {
00546 std::string::size_type fpos = line.find_first_of(']');
00547 std::string::size_type lpos = line.find_last_of(']');
00548 if (fpos == std::string::npos || lpos == std::string::npos ||
00549 fpos != lpos)
00550 {
00551 throw error(linecount, parse_error::INVALID_GROUP, line);
00552 }
00553 group = line.substr(1, fpos - 1);
00554
00555 if (group.length() == 0)
00556 {
00557 throw error(linecount, parse_error::INVALID_GROUP, line);
00558 }
00559
00560
00561 if (tmp.has_group(group))
00562 {
00563 error e(linecount, parse_error::DUPLICATE_GROUP, group);
00564 log_warning() << e.what() << std::endl;
00565 }
00566 else
00567 tmp.set_group(group, comment);
00568 comment.clear();
00569 }
00570 else
00571 {
00572 std::string::size_type pos = line.find_first_of('=');
00573 if (pos == std::string::npos)
00574 {
00575 throw error(linecount, parse_error::INVALID_LINE, line);
00576 }
00577 if (pos == 0)
00578 {
00579 throw error(linecount, parse_error::NO_KEY, line);
00580 }
00581 key = line.substr(0, pos);
00582 if (pos == line.length() - 1)
00583 value = "";
00584 else
00585 value = line.substr(pos + 1);
00586
00587
00588 if (group.empty())
00589 {
00590 throw error(linecount, parse_error::NO_GROUP, line);
00591 }
00592
00593
00594 if (tmp.has_key(group, key))
00595 {
00596 error e(linecount, group, parse_error::DUPLICATE_KEY, key);
00597 log_warning() << e.what() << std::endl;
00598 }
00599 else
00600 tmp.set_value(group, key, value, comment);
00601 comment.clear();
00602 }
00603 }
00604
00605 kf += tmp;
00606
00607 return stream;
00608 }
00609
00613 template <class charT, class traits>
00614 friend
00615 std::basic_ostream<charT,traits>&
00616 operator << (std::basic_ostream<charT,traits>& stream,
00617 keyfile const& kf)
00618 {
00619 unsigned int group_count = 0;
00620
00621 for (group_map_type::const_iterator gp = kf.groups.begin();
00622 gp != kf.groups.end();
00623 ++gp, ++group_count)
00624 {
00625 if (group_count > 0)
00626 stream << '\n';
00627
00628 group_type const& group = gp->second;
00629 std::string const& groupname = std::tr1::get<0>(group);
00630 std::string const& comment = std::tr1::get<2>(group);
00631
00632 if (comment.length() > 0)
00633 print_comment(comment, stream);
00634
00635 stream << '[' << groupname << ']' << '\n';
00636
00637 item_map_type const& items(std::tr1::get<1>(group));
00638 for (item_map_type::const_iterator it = items.begin();
00639 it != items.end();
00640 ++it)
00641 {
00642 item_type const& item = it->second;
00643 std::string const& key(std::tr1::get<0>(item));
00644 std::string const& value(std::tr1::get<1>(item));
00645 std::string const& comment(std::tr1::get<2>(item));
00646
00647 if (comment.length() > 0)
00648 print_comment(comment, stream);
00649
00650 stream << key << '=' << value << '\n';
00651 }
00652 }
00653
00654 return stream;
00655 }
00656
00657 private:
00664 const group_type *
00665 find_group (std::string const& group) const;
00666
00673 group_type *
00674 find_group (std::string const& group);
00675
00683 const item_type *
00684 find_item (std::string const& group,
00685 std::string const& key) const;
00686
00694 item_type *
00695 find_item (std::string const& group,
00696 std::string const& key);
00697
00706 void
00707 check_priority (std::string const& group,
00708 std::string const& key,
00709 priority priority,
00710 bool valid) const;
00711
00719 static void
00720 print_comment (std::string const& comment,
00721 std::ostream& stream);
00722
00724 group_map_type groups;
00726 char separator;
00727 };
00728
00729 }
00730
00731 #endif
00732
00733
00734
00735
00736
00737