sbuild  1.7.1
keyfile.h
1 /* Copyright © 2005-2013 Roger Leigh <rleigh@debian.org>
2  *
3  * schroot is free software: you can redistribute it and/or modify it
4  * under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * schroot is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see
15  * <http://www.gnu.org/licenses/>.
16  *
17  *********************************************************************/
18 
19 #ifndef SBUILD_KEYFILE_H
20 #define SBUILD_KEYFILE_H
21 
22 #include <sbuild/i18n.h>
23 #include <sbuild/log.h>
24 #include <sbuild/parse-error.h>
25 #include <sbuild/parse-value.h>
26 #include <sbuild/types.h>
27 #include <sbuild/util.h>
28 
29 #include <cassert>
30 #include <map>
31 #include <string>
32 #include <sstream>
33 #include <tuple>
34 
35 #include <boost/format.hpp>
36 #include <boost/any.hpp>
37 
38 namespace sbuild
39 {
40 
46  class keyfile
47  {
48  public:
50  enum priority
51  {
57  };
58 
61  {
83  };
84 
87 
89  typedef std::string group_name_type;
90 
92  typedef std::string key_type;
93 
95  typedef std::string value_type;
96 
98  typedef std::string comment_type;
99 
101  typedef unsigned int size_type;
102 
104  typedef std::vector<group_name_type> group_list;
105 
107  typedef std::vector<value_type> value_list;
108 
109  protected:
111  typedef boost::any internal_value_type;
112 
114  typedef std::tuple<key_type,internal_value_type,comment_type,size_type>
116 
118  typedef std::map<key_type,item_type> item_map_type;
119 
121  typedef std::tuple<group_name_type,item_map_type,comment_type,size_type> group_type;
122 
124  typedef std::map<group_name_type,group_type> group_map_type;
125 
127  typedef std::vector<key_type> key_list;
128 
129  public:
131  keyfile ();
132 
134  virtual ~keyfile ();
135 
142  group_list
143  get_groups () const;
144 
152  key_list
153  get_keys (const group_name_type& group) const;
154 
163  void
165  const key_list& keys) const;
166 
173  bool
174  has_group (const group_name_type& group) const;
175 
183  bool
184  has_key (const group_name_type& group,
185  const key_type& key) const;
186 
194  void
196  const comment_type& comment);
197 
206  void
208  const comment_type& comment,
209  size_type line);
210 
218  get_comment (const group_name_type& group) const;
219 
229  const key_type& key) const;
230 
237  size_type
238  get_line (const group_name_type& group) const;
239 
247  size_type
249  const key_type& key) const;
250 
261  template <typename T>
262  bool
264  const key_type& key,
265  T& value) const
266  {
267  log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
268  << ", key=" << key << std::endl;
269  const item_type *found_item = find_item(group, key);
270  if (found_item)
271  {
272  const internal_value_type& strval(std::get<1>(*found_item));
273  try
274  {
275  parse_value(boost::any_cast<std::string const&>(strval), value);
276  return true;
277  }
278  catch (const parse_value_error& e)
279  {
280  size_type line = get_line(group, key);
281  if (line)
282  {
283  error ep(line, group, key, PASSTHROUGH_LGK, e);
285  }
286  else
287  {
288  error ep(group, key, PASSTHROUGH_GK, e);
290  }
291  return false;
292  }
293  }
294  log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
295  return false;
296  }
297 
310  template <typename T>
311  bool
313  const key_type& key,
315  T& value) const
316  {
317  bool status = get_value(group, key, value);
318  check_priority(group, key, priority, status);
319  return status;
320  }
321 
331  bool
333  const key_type& key,
334  value_type& value) const;
335 
347  bool
349  const key_type& key,
351  value_type& value) const;
352 
363  bool
365  const key_type& key,
366  const std::string& locale,
367  value_type& value) const;
368 
382  bool
384  const key_type& key,
385  const std::string& locale,
387  value_type& value) const;
388 
401  template <typename C>
402  bool
404  const key_type& key,
405  C& container) const
406  {
407  value_type item_value;
408  if (get_value(group, key, item_value))
409  {
410  value_list items = split_string(item_value,
411  this->separator);
412  for (const auto& item : items)
413  {
414  typename C::value_type tmp;
415 
416  try
417  {
418  parse_value(item, tmp);
419  }
420  catch (const parse_value_error& e)
421  {
422  size_type line = get_line(group, key);
423  if (line)
424  {
425  error ep(line, group, key, PASSTHROUGH_LGK, e);
427  }
428  else
429  {
430  error ep(group, key, PASSTHROUGH_GK, e);
432  }
433  return false;
434  }
435 
436  container.push_back(tmp);
437  }
438  return true;
439  }
440  return false;
441  }
442 
457  template <typename C>
458  bool
460  const key_type& key,
462  C& container) const
463  {
464  bool status = get_list_value(group, key, container);
465  check_priority(group, key, priority, status);
466  return status;
467  }
468 
481  template <typename C>
482  bool
484  const key_type& key,
485  C& container) const
486  {
487  value_type item_value;
488  if (get_value(group, key, item_value))
489  {
490  value_list items = split_string(item_value,
491  this->separator);
492  for (const auto& item : items)
493  {
494  typename C::value_type tmp;
495 
496  try
497  {
498  parse_value(item, tmp);
499  }
500  catch (const parse_value_error& e)
501  {
502  size_type line = get_line(group, key);
503  if (line)
504  {
505  error ep(line, group, key, PASSTHROUGH_LGK, e);
507  }
508  else
509  {
510  error ep(group, key, PASSTHROUGH_GK, e);
512  }
513  return false;
514  }
515 
516  container.insert(tmp);
517  }
518  return true;
519  }
520  return false;
521  }
522 
537  template <typename C>
538  bool
540  const key_type& key,
542  C& container) const
543  {
544  bool status = get_set_value(group, key, container);
545  check_priority(group, key, priority, status);
546  return status;
547  }
548 
557  template <typename T>
558  void
560  const key_type& key,
561  T const& value)
562  {
563  set_value(group, key, value, comment_type());
564  }
565 
575  template <typename T>
576  void
578  const key_type& key,
579  T const& value,
580  const comment_type& comment)
581  {
582  set_value(group, key, value, comment, 0);
583  }
584 
585  protected:
595  void
597  const key_type& key,
598  const internal_value_type& value,
599  const comment_type& comment,
600  size_type line)
601  {
602  set_group(group, "");
603  group_type *found_group = find_group(group);
604  assert (found_group != 0); // should not fail
605 
606  item_map_type& items = std::get<1>(*found_group);
607 
608  typename item_map_type::iterator pos = items.find(key);
609  if (pos != items.end())
610  items.erase(pos);
611  items.insert
612  (typename item_map_type::value_type(key,
613  item_type(key, value,
614  comment, line)));
615  }
616  public:
617 
628  template <typename T>
629  void
631  const key_type& key,
632  T const& value,
633  const comment_type& comment,
634  size_type line)
635  {
636  std::ostringstream os;
637  os.imbue(std::locale::classic());
638  os << std::boolalpha << value;
639 
640  set_group(group, "");
641  group_type *found_group = find_group(group);
642  assert (found_group != 0); // should not fail
643 
644  item_map_type& items = std::get<1>(*found_group);
645 
646  typename item_map_type::iterator pos = items.find(key);
647  if (pos != items.end())
648  items.erase(pos);
649  items.insert
650  (typename item_map_type::value_type(key,
651  item_type(key, os.str(),
652  comment, line)));
653  }
654 
664  template <typename I>
665  void
667  const key_type& key,
668  I begin,
669  I end)
670  {
671  set_list_value(group, key, begin, end, comment_type());
672  }
673 
684  template <typename I>
685  void
687  const key_type& key,
688  I begin,
689  I end,
690  const comment_type& comment)
691  {
692  set_list_value (group, key, begin, end, comment, 0);
693  }
694 
706  template <typename I>
707  void
709  const key_type& key,
710  I begin,
711  I end,
712  const comment_type& comment,
713  size_type line)
714  {
715  value_type strval;
716 
717  for (I pos = begin; pos != end;)
718  {
719  std::ostringstream os;
720  os.imbue(std::locale::classic());
721  os << std::boolalpha << *pos;
722  if (os)
723  {
724  strval += os.str();
725  if (++pos != end)
726  strval += this->separator;
727  }
728  }
729 
730  set_value (group, key, strval, comment, line);
731  }
732 
742  template <typename I>
743  void
745  const key_type& key,
746  I begin,
747  I end)
748  {
749  std::vector<typename std::iterator_traits<I>::value_type> l(begin, end);
750  std::sort(l.begin(), l.end());
751  set_list_value(group, key, l.begin(), l.end());
752  }
753 
764  template <typename I>
765  void
767  const key_type& key,
768  I begin,
769  I end,
770  const comment_type& comment)
771  {
772  std::vector<typename std::iterator_traits<I>::value_type> l(begin, end);
773  std::sort(l.begin(), l.end());
774  set_list_value(group, key, l.begin(), l.end(), comment);
775  }
776 
788  template <typename I>
789  void
791  const key_type& key,
792  I begin,
793  I end,
794  const comment_type& comment,
795  size_type line)
796  {
797  std::vector<typename std::iterator_traits<I>::value_type> l(begin, end);
798  std::sort(l.begin(), l.end());
799  set_list_value(group, key, l.begin(), l.end(), comment, line);
800  }
801 
807  void
809 
816  void
818  const key_type& key);
819 
826  keyfile&
827  operator += (const keyfile& rhs);
828 
836  friend keyfile
837  operator + (const keyfile& lhs,
838  const keyfile& rhs);
839 
840  protected:
847  const group_type *
848  find_group (const group_name_type& group) const;
849 
856  group_type *
858 
866  const item_type *
868  const key_type& key) const;
869 
877  item_type *
879  const key_type& key);
880 
889  void
891  const key_type& key,
893  bool valid) const;
894 
899 
900  public:
913  template<class C, typename T>
914  static void
915  set_object_value (C const& object,
916  T (C::* method)() const,
917  keyfile& keyfile,
918  const group_name_type& group,
919  const key_type& key)
920  {
921  try
922  {
923  if (method)
924  keyfile.set_value(group, key, (object.*method)());
925  }
926  catch (const std::runtime_error& e)
927  {
928  throw error(group, key, PASSTHROUGH_GK, e);
929  }
930  }
931 
944  template<class C, typename T>
945  static void
946  set_object_value (C const& object,
947  T const& (C::* method)() const,
948  keyfile& keyfile,
949  const group_name_type& group,
950  const key_type& key)
951  {
952  try
953  {
954  if (method)
955  keyfile.set_value(group, key, (object.*method)());
956  }
957  catch (const std::runtime_error& e)
958  {
959  throw error(group, key, PASSTHROUGH_GK, e);
960  }
961  }
962 
976  template<class C, typename T>
977  static void
978  set_object_list_value (C const& object,
979  T (C::* method)() const,
980  keyfile& keyfile,
981  const group_name_type& group,
982  const key_type& key)
983  {
984  try
985  {
986  if (method)
987  keyfile.set_list_value(group, key,
988  (object.*method)().begin(),
989  (object.*method)().end());
990  }
991  catch (const std::runtime_error& e)
992  {
993  throw error(group, key, PASSTHROUGH_GK, e);
994  }
995  }
996 
1011  template<class C, typename T>
1012  static void
1013  set_object_list_value (C const& object,
1014  T const& (C::* method)() const,
1015  keyfile& keyfile,
1016  const group_name_type& group,
1017  const key_type& key)
1018  {
1019  try
1020  {
1021  if (method)
1022  keyfile.set_list_value(group, key,
1023  (object.*method)().begin(),
1024  (object.*method)().end());
1025  }
1026  catch (const std::runtime_error& e)
1027  {
1028  throw error(group, key, PASSTHROUGH_GK, e);
1029  }
1030  }
1031 
1045  template<class C, typename T>
1046  static void
1047  set_object_set_value (C const& object,
1048  T (C::* method)() const,
1049  keyfile& keyfile,
1050  const group_name_type& group,
1051  const key_type& key)
1052  {
1053  try
1054  {
1055  if (method)
1056  keyfile.set_set_value(group, key,
1057  (object.*method)().begin(),
1058  (object.*method)().end());
1059  }
1060  catch (const std::runtime_error& e)
1061  {
1062  throw error(group, key, PASSTHROUGH_GK, e);
1063  }
1064  }
1065 
1080  template<class C, typename T>
1081  static void
1082  set_object_set_value (C const& object,
1083  T const& (C::* method)() const,
1084  keyfile& keyfile,
1085  const group_name_type& group,
1086  const key_type& key)
1087  {
1088  try
1089  {
1090  if (method)
1091  keyfile.set_set_value(group, key,
1092  (object.*method)().begin(),
1093  (object.*method)().end());
1094  }
1095  catch (const std::runtime_error& e)
1096  {
1097  throw error(group, key, PASSTHROUGH_GK, e);
1098  }
1099  }
1100 
1115  template<class C, typename T>
1116  static void
1117  get_object_value (C& object,
1118  void (C::* method)(T param),
1119  const keyfile& keyfile,
1120  const group_name_type& group,
1121  const key_type& key,
1123  {
1124  try
1125  {
1126  T value;
1127  if (keyfile.get_value(group, key, priority, value)
1128  && method)
1129  (object.*method)(value);
1130  }
1131  catch (const std::runtime_error& e)
1132  {
1133  size_type line = keyfile.get_line(group, key);
1134  if (line)
1135  throw error(line, group, key, PASSTHROUGH_LGK, e);
1136  else
1137  throw error(group, key, PASSTHROUGH_GK, e);
1138  }
1139  }
1140 
1155  template<class C, typename T>
1156  static void
1157  get_object_value (C& object,
1158  void (C::* method)(T const& param),
1159  const keyfile& keyfile,
1160  const group_name_type& group,
1161  const key_type& key,
1163  {
1164  try
1165  {
1166  T value;
1167  if (keyfile.get_value(group, key, priority, value)
1168  && method)
1169  (object.*method)(value);
1170  }
1171  catch (const std::runtime_error& e)
1172  {
1173  size_type line = keyfile.get_line(group, key);
1174  if (line)
1175  throw error(line, group, key, PASSTHROUGH_LGK, e);
1176  else
1177  throw error(group, key, PASSTHROUGH_GK, e);
1178  }
1179  }
1180 
1195  template<class C, typename T>
1196  static void
1198  void (C::* method)(T param),
1199  const keyfile& keyfile,
1200  const group_name_type& group,
1201  const key_type& key,
1203  {
1204  try
1205  {
1206  T value;
1207  if (keyfile.get_list_value(group, key, priority, value)
1208  && method)
1209  (object.*method)(value);
1210  }
1211  catch (const std::runtime_error& e)
1212  {
1213  size_type line = keyfile.get_line(group, key);
1214  if (line)
1215  throw error(line, group, key, PASSTHROUGH_LGK, e);
1216  else
1217  throw error(group, key, PASSTHROUGH_GK, e);
1218  throw error(keyfile.get_line(group, key),
1219  group, key, e);
1220  }
1221  }
1222 
1238  template<class C, typename T>
1239  static void
1241  void (C::* method)(T const& param),
1242  const keyfile& keyfile,
1243  const group_name_type& group,
1244  const key_type& key,
1246  {
1247  try
1248  {
1249  T value;
1250  if (keyfile.get_list_value(group, key, priority, value)
1251  && method)
1252  (object.*method)(value);
1253  }
1254  catch (const std::runtime_error& e)
1255  {
1256  size_type line = keyfile.get_line(group, key);
1257  if (line)
1258  throw error(line, group, key, PASSTHROUGH_LGK, e);
1259  else
1260  throw error(group, key, PASSTHROUGH_GK, e);
1261  throw error(keyfile.get_line(group, key),
1262  group, key, e);
1263  }
1264  }
1265 
1280  template<class C, typename T>
1281  static void
1283  void (C::* method)(T param),
1284  const keyfile& keyfile,
1285  const group_name_type& group,
1286  const key_type& key,
1288  {
1289  try
1290  {
1291  T value;
1292  if (keyfile.get_set_value(group, key, priority, value)
1293  && method)
1294  (object.*method)(value);
1295  }
1296  catch (const std::runtime_error& e)
1297  {
1298  size_type line = keyfile.get_line(group, key);
1299  if (line)
1300  throw error(line, group, key, PASSTHROUGH_LGK, e);
1301  else
1302  throw error(group, key, PASSTHROUGH_GK, e);
1303  throw error(keyfile.get_line(group, key),
1304  group, key, e);
1305  }
1306  }
1307 
1323  template<class C, typename T>
1324  static void
1326  void (C::* method)(T const& param),
1327  const keyfile& keyfile,
1328  const group_name_type& group,
1329  const key_type& key,
1331  {
1332  try
1333  {
1334  T value;
1335  if (keyfile.get_set_value(group, key, priority, value)
1336  && method)
1337  (object.*method)(value);
1338  }
1339  catch (const std::runtime_error& e)
1340  {
1341  size_type line = keyfile.get_line(group, key);
1342  if (line)
1343  throw error(line, group, key, PASSTHROUGH_LGK, e);
1344  else
1345  throw error(group, key, PASSTHROUGH_GK, e);
1346  throw error(keyfile.get_line(group, key),
1347  group, key, e);
1348  }
1349  }
1350  };
1351 
1352 }
1353 
1354 #endif /* SBUILD_KEYFILE_H */
1355 
1356 /*
1357  * Local Variables:
1358  * mode:C++
1359  * End:
1360  */