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 <cassert>
00024 #include <iostream>
00025 #include <map>
00026 #include <string>
00027 #include <sstream>
00028 #include <tr1/tuple>
00029
00030 #include <boost/format.hpp>
00031
00032 #include "sbuild-error.h"
00033 #include "sbuild-i18n.h"
00034 #include "sbuild-log.h"
00035 #include "sbuild-parse-value.h"
00036 #include "sbuild-types.h"
00037 #include "sbuild-util.h"
00038
00039 namespace sbuild
00040 {
00041
00053 class keyfile
00054 {
00055 private:
00057 typedef std::tr1::tuple<std::string,std::string,std::string> item_type;
00058
00060 typedef std::map<std::string,item_type> item_map_type;
00061
00063 typedef std::tr1::tuple<std::string,item_map_type,std::string> group_type;
00064
00066 typedef std::map<std::string,group_type> group_map_type;
00067
00068 public:
00070 enum priority
00071 {
00072 PRIORITY_OPTIONAL,
00073 PRIORITY_REQUIRED,
00074 PRIORITY_DISALLOWED,
00075 PRIORITY_DEPRECATED,
00076 PRIORITY_OBSOLETE
00077 };
00078
00080 typedef runtime_error_custom<keyfile> error;
00081
00083 keyfile();
00084
00090 keyfile(std::string const& file);
00091
00097 keyfile(std::istream& stream);
00098
00100 virtual ~keyfile();
00101
00108 string_list
00109 get_groups() const;
00110
00118 string_list
00119 get_keys(std::string const& group) const;
00120
00127 bool
00128 has_group(std::string const& group) const;
00129
00137 bool
00138 has_key(std::string const& group,
00139 std::string const& key) const;
00140
00141
00142 private:
00151 void
00152 check_priority (std::string const& group,
00153 std::string const& key,
00154 priority priority,
00155 bool valid) const;
00156
00157 public:
00168 template <typename T>
00169 bool
00170 get_value(std::string const& group,
00171 std::string const& key,
00172 T& value) const
00173 {
00174 log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
00175 << ", key=" << key << std::endl;
00176 const item_type *found_item = find_item(group, key);
00177 if (found_item)
00178 {
00179 std::string const& strval(std::tr1::get<1>(*found_item));
00180 return parse_value(strval, value);
00181 }
00182 log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
00183 return false;
00184 }
00185
00198 template <typename T>
00199 bool
00200 get_value(std::string const& group,
00201 std::string const& key,
00202 priority priority,
00203 T& value) const
00204 {
00205 bool status = get_value(group, key, value);
00206 check_priority(group, key, priority, status);
00207 return status;
00208 }
00209
00221 template <typename T, template <typename T> class C>
00222 bool
00223 get_list_value(std::string const& group,
00224 std::string const& key,
00225 C<T>& value) const
00226 {
00227 std::string item_value;
00228 if (get_value(group, key, item_value))
00229 {
00230 C<T> tmplist;
00231 string_list items = split_string(item_value, this->separator);
00232 for (string_list::const_iterator pos = items.begin();
00233 pos != items.end();
00234 ++pos
00235 )
00236 {
00237 T tmpval;
00238 if (parse_value(*pos, tmpval) == false)
00239 return false;
00240 tmplist.push_back(tmpval);
00241 }
00242 value = tmplist;
00243 return true;
00244 }
00245 return false;
00246 }
00247
00261 template <typename T, template <typename T> class C>
00262 bool
00263 get_list_value(std::string const& group,
00264 std::string const& key,
00265 priority priority,
00266 C<T>& value) const
00267 {
00268 bool status = get_list_value(group, key, value);
00269 check_priority(group, key, priority, status);
00270 return status;
00271 }
00272
00281 template <typename T>
00282 void
00283 set_value(std::string const& group,
00284 std::string const& key,
00285 T const& value)
00286 {
00287 std::ostringstream os;
00288 os.imbue(std::locale("C"));
00289 os << std::boolalpha << value;
00290
00291 if (!has_group(group))
00292 this->groups.insert
00293 (group_map_type::value_type(group,
00294 group_type(group,
00295 item_map_type(),
00296 std::string())));
00297 group_type *found_group = find_group(group);
00298 assert (found_group != 0);
00299
00300 item_map_type& items = std::tr1::get<1>(*found_group);
00301
00302 item_map_type::iterator pos = items.find(key);
00303 if (pos != items.end())
00304 items.erase(pos);
00305
00306 items.insert
00307 (item_map_type::value_type(key,
00308 item_type(key, os.str(), std::string())));
00309
00310 }
00311
00321 template <typename T, template <typename T> class C>
00322 void
00323 set_list_value(std::string const& group,
00324 std::string const& key,
00325 C<T> const& value)
00326 {
00327 std::string strval;
00328
00329 for (typename C<T>::const_iterator pos = value.begin();
00330 pos != value.end();
00331 ++ pos)
00332 {
00333 std::ostringstream os;
00334 os.imbue(std::locale("C"));
00335 os << std::boolalpha << *pos;
00336 if (os)
00337 {
00338 strval += os.str();
00339 if (pos + 1 != value.end())
00340 strval += this->separator;
00341 }
00342 }
00343
00344 set_value (group, key, strval);
00345 }
00346
00352 void
00353 remove_group(std::string const& group);
00354
00361 void
00362 remove_key(std::string const& group,
00363 std::string const& key);
00364
00368 template <class charT, class traits>
00369 friend
00370 std::basic_istream<charT,traits>&
00371 operator >> (std::basic_istream<charT,traits>& stream, keyfile& kf)
00372 {
00373 size_t linecount = 0;
00374 std::string line;
00375 std::string group;
00376 std::string group_comment;
00377 std::string comment;
00378 std::string key;
00379 std::string value;
00380
00381 while (std::getline(stream, line))
00382 {
00383 if (line[0] == '#')
00384 {
00385 if (!comment.empty())
00386 comment += '\n';
00387 comment += line.substr(1);
00388 }
00389 else if (line[0] == '[')
00390 {
00391 std::string::size_type fpos = line.find_first_of(']');
00392 std::string::size_type lpos = line.find_last_of(']');
00393 if (fpos == std::string::npos || fpos != lpos)
00394 {
00395 boost::format fmt(_("Line %1%: invalid group entry: %2%"));
00396 fmt % linecount % line;
00397 throw error(fmt);
00398 }
00399 group = line.substr(1, fpos - 1);
00400
00401 if (!comment.empty())
00402 {
00403 if (!group_comment.empty())
00404 group_comment += '\n';
00405 group_comment += comment;
00406 comment.clear();
00407 }
00408
00409
00410
00411 }
00412 else if (line.length() == 0)
00413 {
00414
00415 }
00416 else
00417 {
00418 std::string::size_type pos = line.find_first_of('=');
00419 if (pos == std::string::npos)
00420 {
00421 boost::format fmt(_("Line %1%: invalid line: %2%"));
00422 fmt % linecount % line;
00423 throw error(fmt);
00424 }
00425 if (pos == 0)
00426 {
00427 boost::format fmt(_("Line %1%: no key specified: %2%"));
00428 fmt % linecount % line;
00429 throw error(fmt);
00430 }
00431 key = line.substr(0, pos);
00432 if (pos == line.length() - 1)
00433 value = "";
00434 else
00435 value = line.substr(pos + 1);
00436
00437
00438 kf.set_value(group, key, value);
00439
00440
00441 }
00442
00443 linecount++;
00444 }
00445
00446 return stream;
00447 }
00448
00449 private:
00457 static void
00458 print_comment(std::string const& comment,
00459 std::ostream& stream);
00460
00461 public:
00465 template <class charT, class traits>
00466 friend
00467 std::basic_ostream<charT,traits>&
00468 operator << (std::basic_ostream<charT,traits>& stream, keyfile const& kf)
00469 {
00470 unsigned int group_count = 0;
00471
00472 for (group_map_type::const_iterator gp = kf.groups.begin();
00473 gp != kf.groups.end();
00474 ++gp, ++group_count)
00475 {
00476 if (group_count > 0)
00477 stream << '\n';
00478
00479 group_type const& group = gp->second;
00480 std::string const& groupname = std::tr1::get<0>(group);
00481 std::string const& comment = std::tr1::get<2>(group);
00482
00483 if (comment.length() > 0)
00484 print_comment(comment, stream);
00485
00486 stream << '[' << groupname << ']' << '\n';
00487
00488 item_map_type const& items(std::tr1::get<1>(group));
00489 for (item_map_type::const_iterator it = items.begin();
00490 it != items.end();
00491 ++it)
00492 {
00493 item_type const& item = it->second;
00494 std::string const& key(std::tr1::get<0>(item));
00495 std::string const& value(std::tr1::get<1>(item));
00496 std::string const& comment(std::tr1::get<2>(item));
00497
00498 if (comment.length() > 0)
00499 print_comment(comment, stream);
00500
00501 stream << key << '=' << value << '\n';
00502 }
00503 }
00504
00505 return stream;
00506 }
00507
00508 private:
00515 const group_type *
00516 find_group(std::string const& group) const;
00517
00524 group_type *
00525 find_group(std::string const& group);
00526
00534 const item_type *
00535 find_item(std::string const& group,
00536 std::string const& key) const;
00537
00545 item_type *
00546 find_item(std::string const& group,
00547 std::string const& key);
00548
00550 group_map_type groups;
00552 char separator;
00553 };
00554
00555 }
00556
00557 #endif
00558
00559
00560
00561
00562
00563