00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021
00022 #include "sbuild-keyfile.h"
00023
00024 #include <fstream>
00025
00026 #include <boost/format.hpp>
00027
00028 using boost::format;
00029 using namespace sbuild;
00030
00031 namespace
00032 {
00033
00034 typedef std::pair<keyfile::error_code,const char *> emap;
00035
00040 emap init_errors[] =
00041 {
00042
00043 emap(keyfile::BAD_FILE, N_("Can't open file '%1%'")),
00044
00045
00046
00047 emap(keyfile::DEPRECATED_KEY, N_("line %1% [%2%]: Deprecated key '%4%' used")),
00048
00049
00050 emap(keyfile::DEPRECATED_KEY_NL, N_("[%1%]: Deprecated key '%4%' used")),
00051
00052
00053
00054 emap(keyfile::DISALLOWED_KEY, N_("line %1% [%2%]: Disallowed key '%4%' used")),
00055
00056
00057 emap(keyfile::DISALLOWED_KEY_NL, N_("[%1%]: Disallowed key '%4%' used")),
00058
00059
00060 emap(keyfile::DUPLICATE_GROUP, N_("line %1%: Duplicate group '%4%'")),
00061
00062
00063
00064 emap(keyfile::DUPLICATE_KEY, N_("line %1% [%2%]: Duplicate key '%4%'")),
00065
00066
00067 emap(keyfile::INVALID_GROUP, N_("line %1%: Invalid group: \"%4%\"")),
00068
00069
00070 emap(keyfile::INVALID_LINE, N_("line %1%: Invalid line: \"%4%\"")),
00071
00072
00073
00074 emap(keyfile::MISSING_KEY, N_("line %1% [%2%]: Required key '%4%' is missing")),
00075
00076
00077 emap(keyfile::MISSING_KEY_NL, N_("[%1%]: Required key '%4%' is missing")),
00078
00079
00080 emap(keyfile::NO_GROUP, N_("line %1%: No group specified: \"%4%\"")),
00081
00082
00083 emap(keyfile::NO_KEY, N_("line %1%: No key specified: \"%4%\"")),
00084
00085
00086
00087 emap(keyfile::OBSOLETE_KEY, N_("line %1% [%2%]: Obsolete key '%4%' used")),
00088
00089
00090 emap(keyfile::OBSOLETE_KEY_NL, N_("[%1%]: Obsolete key '%4%' used")),
00091
00092
00093 emap(keyfile::PASSTHROUGH_G, N_("[%1%]: %4%")),
00094
00095
00096
00097 emap(keyfile::PASSTHROUGH_GK, N_("[%1%] %2%: %4%")),
00098
00099
00100
00101 emap(keyfile::PASSTHROUGH_LG, N_("line %1% [%2%]: %4%")),
00102
00103
00104
00105
00106 emap(keyfile::PASSTHROUGH_LGK, N_("line %1% [%2%] %3%: %4%"))
00107 };
00108
00109 }
00110
00111 template<>
00112 error<keyfile::error_code>::map_type
00113 error<keyfile::error_code>::error_strings
00114 (init_errors,
00115 init_errors + (sizeof(init_errors) / sizeof(init_errors[0])));
00116
00117 keyfile::keyfile ():
00118 groups(),
00119 separator(',')
00120 {
00121 }
00122
00123 keyfile::keyfile (std::string const& file):
00124 groups(),
00125 separator(',')
00126 {
00127 std::ifstream fs(file.c_str());
00128 if (fs)
00129 {
00130 fs.imbue(std::locale::classic());
00131 fs >> *this;
00132 }
00133 else
00134 {
00135 throw error(file, BAD_FILE);
00136 }
00137 }
00138
00139 keyfile::keyfile (std::istream& stream):
00140 groups(),
00141 separator(',')
00142 {
00143 stream >> *this;
00144 }
00145
00146 keyfile::~keyfile()
00147 {
00148 }
00149
00150 string_list
00151 keyfile::get_groups () const
00152 {
00153 string_list ret;
00154
00155 for (group_map_type::const_iterator pos = this->groups.begin();
00156 pos != this->groups.end();
00157 ++pos)
00158 ret.push_back(pos->first);
00159
00160 return ret;
00161 }
00162
00163 string_list
00164 keyfile::get_keys (std::string const& group) const
00165 {
00166 string_list ret;
00167
00168 const group_type *found_group = find_group(group);
00169 if (found_group)
00170 {
00171 item_map_type const& items(std::tr1::get<1>(*found_group));
00172 for (item_map_type::const_iterator pos = items.begin();
00173 pos != items.end();
00174 ++pos)
00175 ret.push_back(pos->first);
00176 }
00177
00178 return ret;
00179 }
00180
00181 bool
00182 keyfile::has_group (std::string const& group) const
00183 {
00184 return (find_group(group) != 0);
00185 }
00186
00187 bool
00188 keyfile::has_key (std::string const& group,
00189 std::string const& key) const
00190 {
00191 return (find_item(group, key) != 0);
00192 }
00193
00194 void
00195 keyfile::set_group (std::string const& group,
00196 std::string const& comment)
00197 {
00198 set_group(group, comment, 0);
00199 }
00200
00201 void
00202 keyfile::set_group (std::string const& group,
00203 std::string const& comment,
00204 unsigned int line)
00205 {
00206 if (!has_group(group))
00207 this->groups.insert
00208 (group_map_type::value_type(group,
00209 group_type(group,
00210 item_map_type(),
00211 comment,
00212 line)));
00213 }
00214
00215 std::string
00216 keyfile::get_comment (std::string const& group) const
00217 {
00218 const keyfile::group_type *found_group = find_group(group);
00219 if (found_group)
00220 return std::tr1::get<2>(*found_group);
00221 else
00222 return std::string();
00223 }
00224
00225 std::string
00226 keyfile::get_comment (std::string const& group,
00227 std::string const& key) const
00228 {
00229 const item_type *found_item = find_item(group, key);
00230 if (found_item)
00231 return std::tr1::get<2>(*found_item);
00232 else
00233 return std::string();
00234 }
00235
00236 unsigned int
00237 keyfile::get_line (std::string const& group) const
00238 {
00239 const keyfile::group_type *found_group = find_group(group);
00240 if (found_group)
00241 return std::tr1::get<3>(*found_group);
00242 else
00243 return 0;
00244 }
00245
00246 unsigned int
00247 keyfile::get_line (std::string const& group,
00248 std::string const& key) const
00249 {
00250 const item_type *found_item = find_item(group, key);
00251 if (found_item)
00252 return std::tr1::get<3>(*found_item);
00253 else
00254 return 0;
00255 }
00256
00257 bool
00258 keyfile::get_locale_string (std::string const& group,
00259 std::string const& key,
00260 std::string& value) const
00261 {
00262 std::string localename = std::locale("").name();
00263 std::string::size_type pos;
00264 bool status = false;
00265
00266
00267 if ((pos = localename.find_first_of('.')) != std::string::npos)
00268 localename = localename.substr(0, pos);
00269 status = get_locale_string(group, key, localename, value);
00270
00271
00272 if (status == false &&
00273 (pos = localename.find_first_of('_')) != std::string::npos)
00274 {
00275 localename = localename.substr(0, pos);
00276 status = get_locale_string(group, key, localename, value);
00277 }
00278
00279
00280 if (status == false)
00281 status = get_value(group, key, value);
00282
00283 return status;
00284 }
00285
00286 bool
00287 keyfile::get_locale_string (std::string const& group,
00288 std::string const& key,
00289 priority priority,
00290 std::string& value) const
00291 {
00292 bool status = get_locale_string(group, key, value);
00293 check_priority(group, key, priority, status);
00294 return status;
00295 }
00296
00297 bool
00298 keyfile::get_locale_string (std::string const& group,
00299 std::string const& key,
00300 std::string const& locale,
00301 std::string& value) const
00302 {
00303 std::string lkey = key + '[' + locale + ']';
00304 return get_value(group, lkey, value);
00305 }
00306
00307 bool
00308 keyfile::get_locale_string (std::string const& group,
00309 std::string const& key,
00310 std::string const& locale,
00311 priority priority,
00312 std::string& value) const
00313 {
00314 bool status = get_locale_string(group, key, locale, value);
00315 check_priority(group, key, priority, status);
00316 return status;
00317 }
00318
00319 void
00320 keyfile::remove_group (std::string const& group)
00321 {
00322 group_map_type::iterator pos = this->groups.find(group);
00323 if (pos != this->groups.end())
00324 this->groups.erase(pos);
00325 }
00326
00327 void
00328 keyfile::remove_key (std::string const& group,
00329 std::string const& key)
00330 {
00331 group_type *found_group = find_group(group);
00332 if (found_group)
00333 {
00334 item_map_type& items = std::tr1::get<1>(*found_group);
00335 item_map_type::iterator pos = items.find(key);
00336 if (pos != items.end())
00337 items.erase(pos);
00338 }
00339 }
00340
00341 keyfile&
00342 keyfile::operator += (keyfile const& rhs)
00343 {
00344 for (group_map_type::const_iterator gp = rhs.groups.begin();
00345 gp != rhs.groups.end();
00346 ++gp)
00347 {
00348 group_type const& group = gp->second;
00349 std::string const& groupname = std::tr1::get<0>(group);
00350 std::string const& comment = std::tr1::get<2>(group);
00351 unsigned int const& line = std::tr1::get<3>(group);
00352 set_group(groupname, comment, line);
00353
00354 item_map_type const& items(std::tr1::get<1>(group));
00355 for (item_map_type::const_iterator it = items.begin();
00356 it != items.end();
00357 ++it)
00358 {
00359 item_type const& item = it->second;
00360 std::string const& key(std::tr1::get<0>(item));
00361 std::string const& value(std::tr1::get<1>(item));
00362 std::string const& comment(std::tr1::get<2>(item));
00363 unsigned int const& line(std::tr1::get<3>(item));
00364 set_value(groupname, key, value, comment, line);
00365 }
00366 }
00367 return *this;
00368 }
00369
00370 keyfile
00371 operator + (keyfile const& lhs,
00372 keyfile const& rhs)
00373 {
00374 keyfile ret(lhs);
00375 ret += rhs;
00376 return ret;
00377 }
00378
00379 const keyfile::group_type *
00380 keyfile::find_group (std::string const& group) const
00381 {
00382 group_map_type::const_iterator pos = this->groups.find(group);
00383 if (pos != this->groups.end())
00384 return &pos->second;
00385
00386 return 0;
00387 }
00388
00389 keyfile::group_type *
00390 keyfile::find_group (std::string const& group)
00391 {
00392 group_map_type::iterator pos = this->groups.find(group);
00393 if (pos != this->groups.end())
00394 return &pos->second;
00395
00396 return 0;
00397 }
00398
00399 const keyfile::item_type *
00400 keyfile::find_item (std::string const& group,
00401 std::string const& key) const
00402 {
00403 const group_type *found_group = find_group(group);
00404 if (found_group)
00405 {
00406 item_map_type const& items = std::tr1::get<1>(*found_group);
00407 item_map_type::const_iterator pos = items.find(key);
00408 if (pos != items.end())
00409 return &pos->second;
00410 }
00411
00412 return 0;
00413 }
00414
00415 keyfile::item_type *
00416 keyfile::find_item (std::string const& group,
00417 std::string const& key)
00418 {
00419 group_type *found_group = find_group(group);
00420 if (found_group)
00421 {
00422 item_map_type& items = std::tr1::get<1>(*found_group);
00423 item_map_type::iterator pos = items.find(key);
00424 if (pos != items.end())
00425 return &pos->second;
00426 }
00427
00428 return 0;
00429 }
00430
00431 void
00432 keyfile::print_comment (std::string const& comment,
00433 std::ostream& stream)
00434 {
00435 std::string::size_type last_pos = 0;
00436 std::string::size_type pos = comment.find_first_of('\n', last_pos);
00437
00438 while (1)
00439 {
00440 if (last_pos == pos)
00441 stream << "#\n";
00442 else
00443 stream << '#' << comment.substr(last_pos, pos - last_pos) << '\n';
00444
00445
00446 if (pos < comment.length() - 1)
00447 {
00448 last_pos = pos + 1;
00449 pos = comment.find_first_of('\n', last_pos);
00450 }
00451 else
00452 break;
00453 }
00454 }
00455
00456 void
00457 keyfile::check_priority (std::string const& group,
00458 std::string const& key,
00459 priority priority,
00460 bool valid) const
00461 {
00462 if (valid == false)
00463 {
00464 unsigned int gline = get_line(group);
00465
00466 switch (priority)
00467 {
00468 case PRIORITY_REQUIRED:
00469 {
00470 if (gline)
00471 throw error(gline, group, MISSING_KEY, key);
00472 else
00473 throw error(group, MISSING_KEY_NL, key);
00474 }
00475 break;
00476 default:
00477 break;
00478 }
00479 }
00480 else
00481 {
00482 unsigned int line = get_line(group, key);
00483
00484 switch (priority)
00485 {
00486 case PRIORITY_DEPRECATED:
00487 {
00488 if (line)
00489 {
00490 error e(line, group, DEPRECATED_KEY, key);
00491 e.set_reason(_("This option will be removed in the future"));
00492 log_exception_warning(e);
00493 }
00494 else
00495 {
00496 error e(group, DEPRECATED_KEY_NL, key);
00497 e.set_reason(_("This option will be removed in the future"));
00498 log_exception_warning(e);
00499 }
00500 }
00501 break;
00502 case PRIORITY_OBSOLETE:
00503 {
00504 if (line)
00505 {
00506 error e(line, group, OBSOLETE_KEY, key);
00507 e.set_reason(_("This option has been removed, and no longer has any effect"));
00508 log_exception_warning(e);
00509 }
00510 else
00511 {
00512 error e(group, OBSOLETE_KEY_NL, key);
00513 e.set_reason(_("This option has been removed, and no longer has any effect"));
00514 log_exception_warning(e);
00515 }
00516 }
00517 break;
00518 case PRIORITY_DISALLOWED:
00519 {
00520 if (line)
00521 throw error(line, group, DISALLOWED_KEY, key);
00522 else
00523 throw error(group, DISALLOWED_KEY_NL, key);
00524 }
00525 break;
00526 default:
00527 break;
00528 }
00529 }
00530 }