sbuild-keyfile.cc

Go to the documentation of this file.
00001 /* Copyright © 2005-2006  Roger Leigh <rleigh@debian.org>
00002  *
00003  * schroot is free software; you can redistribute it and/or modify it
00004  * under the terms of the GNU General Public License as published by
00005  * the Free Software Foundation; either version 2 of the License, or
00006  * (at your option) any later version.
00007  *
00008  * schroot is distributed in the hope that it will be useful, but
00009  * WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011  * General Public License for more details.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * along with this program; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00016  * MA  02111-1307  USA
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       // TRANSLATORS: %1% = file
00043       emap(keyfile::BAD_FILE,          N_("Can't open file '%1%'")),
00044       // TRANSLATORS: %1% = line number in configuration file
00045       // TRANSLATORS: %2% = group name ("[groupname]" in configuration file)
00046       // TRANSLATORS: %4% = key name ("keyname=value" in configuration file)
00047       emap(keyfile::DEPRECATED_KEY,    N_("line %1% [%2%]: Deprecated key '%4%' used")),
00048       // TRANSLATORS: %1% = group name ("[groupname]" in configuration file)
00049       // TRANSLATORS: %4% = key name ("keyname=value" in configuration file)
00050       emap(keyfile::DEPRECATED_KEY_NL, N_("[%1%]: Deprecated key '%4%' used")),
00051       // TRANSLATORS: %1% = line number in configuration file
00052       // TRANSLATORS: %2% = group name ("[groupname]" in configuration file)
00053       // TRANSLATORS: %4% = key name ("keyname=value" in configuration file)
00054       emap(keyfile::DISALLOWED_KEY,    N_("line %1% [%2%]: Disallowed key '%4%' used")),
00055       // TRANSLATORS: %1% = group name ("[groupname]" in configuration file)
00056       // TRANSLATORS: %4% = key name ("keyname=value" in configuration file)
00057       emap(keyfile::DISALLOWED_KEY_NL, N_("[%1%]: Disallowed key '%4%' used")),
00058       // TRANSLATORS: %1% = line number in configuration file
00059       // TRANSLATORS: %4% = group name ("[groupname]" in configuration file)
00060       emap(keyfile::DUPLICATE_GROUP,   N_("line %1%: Duplicate group '%4%'")),
00061       // TRANSLATORS: %1% = line number in configuration file
00062       // TRANSLATORS: %2% = group name ("[groupname]" in configuration file)
00063       // TRANSLATORS: %4% = key name ("keyname=value" in configuration file)
00064       emap(keyfile::DUPLICATE_KEY,     N_("line %1% [%2%]: Duplicate key '%4%'")),
00065       // TRANSLATORS: %1% = line number in configuration file
00066       // TRANSLATORS: %4% = line contents as read from the configuration file
00067       emap(keyfile::INVALID_GROUP,     N_("line %1%: Invalid group: \"%4%\"")),
00068       // TRANSLATORS: %1% = line number in configuration file
00069       // TRANSLATORS: %4% = line contents as read from the configuration file
00070       emap(keyfile::INVALID_LINE,      N_("line %1%: Invalid line: \"%4%\"")),
00071       // TRANSLATORS: %1% = line number in configuration file
00072       // TRANSLATORS: %2% = group name ("[groupname]" in configuration file)
00073       // TRANSLATORS: %4% = key name ("keyname=value" in configuration file)
00074       emap(keyfile::MISSING_KEY,       N_("line %1% [%2%]: Required key '%4%' is missing")),
00075       // TRANSLATORS: %1% = group name ("[groupname]" in configuration file)
00076       // TRANSLATORS: %4% = key name ("keyname=value" in configuration file)
00077       emap(keyfile::MISSING_KEY_NL,    N_("[%1%]: Required key '%4%' is missing")),
00078       // TRANSLATORS: %1% = line number in configuration file
00079       // TRANSLATORS: %4% = line contents as read from the configuration file
00080       emap(keyfile::NO_GROUP,          N_("line %1%: No group specified: \"%4%\"")),
00081       // TRANSLATORS: %1% = line number in configuration file
00082       // TRANSLATORS: %4% = line contents as read from the configuration file
00083       emap(keyfile::NO_KEY,            N_("line %1%: No key specified: \"%4%\"")),
00084       // TRANSLATORS: %1% = line number in configuration file
00085       // TRANSLATORS: %2% = group name ("[groupname]" in configuration file)
00086       // TRANSLATORS: %4% = key name ("keyname=value" in configuration file)
00087       emap(keyfile::OBSOLETE_KEY,      N_("line %1% [%2%]: Obsolete key '%4%' used")),
00088       // TRANSLATORS: %1% = group name ("[groupname]" in configuration file)
00089       // TRANSLATORS: %4% = key name ("keyname=value" in configuration file)
00090       emap(keyfile::OBSOLETE_KEY_NL,   N_("[%1%]: Obsolete key '%4%' used")),
00091       // TRANSLATORS: %1% = group name ("[groupname]" in configuration file)
00092       // TRANSLATORS: %4% = additional details
00093       emap(keyfile::PASSTHROUGH_G,     N_("[%1%]: %4%")),
00094       // TRANSLATORS: %1% = group name ("[groupname]" in configuration file)
00095       // TRANSLATORS: %2% = key name ("keyname=value" in configuration file)
00096       // TRANSLATORS: %4% = additional details
00097       emap(keyfile::PASSTHROUGH_GK,    N_("[%1%] %2%: %4%")),
00098       // TRANSLATORS: %1% = line number in configuration file
00099       // TRANSLATORS: %2% = group name ("[groupname]" in configuration file)
00100       // TRANSLATORS: %4% = additional details
00101       emap(keyfile::PASSTHROUGH_LG,    N_("line %1% [%2%]: %4%")),
00102       // TRANSLATORS: %1% = line number in configuration file
00103       // TRANSLATORS: %2% = group name ("[groupname]" in configuration file)
00104       // TRANSLATORS: %3% = key name ("keyname=value" in configuration file)
00105       // TRANSLATORS: %4% = additional details
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   // Strip off any charset.
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   // Strip off territory.
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   // Fall back to non-localised version.
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       // Find next
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 }

Generated on Sat Jan 27 16:11:03 2007 for schroot by  doxygen 1.5.1