1 /*
2    Copyright (C) 2003 by David White <dave@whitevine.net>
3    Copyright (C) 2005 - 2018 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
4    Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY.
12 
13    See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Routines related to configuration-files / WML.
19  */
20 
21 #include "config.hpp"
22 
23 #include "formatter.hpp"
24 #include "lexical_cast.hpp"
25 #include "log.hpp"
26 #include "utils/const_clone.hpp"
27 #include "utils/functional.hpp"
28 #include "deprecation.hpp"
29 #include "game_version.hpp"
30 
31 #include <algorithm>
32 #include <cstdlib>
33 #include <cstring>
34 #include <deque>
35 #include <istream>
36 #include <locale>
37 
38 #include <boost/variant/apply_visitor.hpp>
39 #include <boost/variant/get.hpp>
40 #include <boost/variant/static_visitor.hpp>
41 #include <boost/variant/variant.hpp>
42 
43 static lg::log_domain log_config("config");
44 #define ERR_CF LOG_STREAM(err, log_config)
45 #define DBG_CF LOG_STREAM(debug, log_config)
46 
47 namespace
48 {
49 // std::map::operator[] does not support heterogeneous lookup so we need this to work around.
50 template<typename Map, typename Key>
map_get(Map & map,Key && key)51 typename Map::mapped_type& map_get(Map& map, Key&& key)
52 {
53 	auto res = map.lower_bound(key);
54 
55 	if(res == map.end() || key != res->first) {
56 		res = map.emplace_hint(res, std::piecewise_construct, std::forward_as_tuple(key), std::tuple<>());
57 	}
58 
59 	return res->second;
60 }
61 
62 // std::map::erase does not support heterogeneous lookup so we need this to work around.
63 template<typename Map, typename Key>
map_erase_key(Map & map,Key && key)64 int map_erase_key(Map& map, Key&& key)
65 {
66 	auto i = map.find(key);
67 	if(i != map.end()) {
68 		map.erase(i);
69 		return 1;
70 	}
71 	return 0;
72 }
73 }
74 
75 struct config_implementation
76 {
77 	/**
78 	 * Implementation for the wrappers for
79 	 * [const] config& child(const std::string& key, const std::string& parent);
80 	 *
81 	 * @tparam T                  A pointer to the config.
82 	 */
83 	template<class T>
childconfig_implementation84 	static utils::const_clone_ref<config, T> child(T config, config_key_type key, const std::string& parent)
85 	{
86 		config->check_valid();
87 
88 		assert(!parent.empty());
89 		assert(parent.front() == '[');
90 		assert(parent.back() == ']');
91 
92 		if(config->has_child(key)) {
93 			return *(config->children_.find(key)->second.front());
94 		}
95 
96 		/**
97 		 * @todo Implement a proper wml_exception here.
98 		 *
99 		 * at the moment there seem to be dependency issues, which i don't want
100 		 * to fix right now.
101 		 */
102 		// FAIL(missing_mandatory_wml_section(parent, key));
103 
104 		std::stringstream sstr;
105 		sstr << "Mandatory WML child »[" << key << "]« missing in »" << parent << "«. Please report this bug.";
106 
107 		throw config::error(sstr.str());
108 	}
109 };
110 
111 /* ** config implementation ** */
112 
113 config config::invalid;
114 
115 const char* config::diff_track_attribute = "__diff_track";
116 
check_valid() const117 void config::check_valid() const
118 {
119 	if(!*this) {
120 		throw error("Mandatory WML child missing yet untested for. Please report.");
121 	}
122 }
123 
check_valid(const config & cfg) const124 void config::check_valid(const config& cfg) const
125 {
126 	if(!*this || !cfg) {
127 		throw error("Mandatory WML child missing yet untested for. Please report.");
128 	}
129 }
130 
config()131 config::config()
132 	: values_()
133 	, children_()
134 	, ordered_children()
135 {
136 }
137 
config(const config & cfg)138 config::config(const config& cfg)
139 	: values_(cfg.values_)
140 	, children_()
141 	, ordered_children()
142 {
143 	append_children(cfg);
144 }
145 
config(config_key_type child)146 config::config(config_key_type child)
147 	: values_()
148 	, children_()
149 	, ordered_children()
150 {
151 	add_child(child);
152 }
153 
~config()154 config::~config()
155 {
156 	clear();
157 }
158 
operator =(const config & cfg)159 config& config::operator=(const config& cfg)
160 {
161 	if(this == &cfg) {
162 		return *this;
163 	}
164 
165 	config tmp(cfg);
166 	swap(tmp);
167 	return *this;
168 }
169 
config(config && cfg)170 config::config(config&& cfg)
171 	: values_(std::move(cfg.values_))
172 	, children_(std::move(cfg.children_))
173 	, ordered_children(std::move(cfg.ordered_children))
174 {
175 }
176 
operator =(config && cfg)177 config& config::operator=(config&& cfg)
178 {
179 	clear();
180 	swap(cfg);
181 	return *this;
182 }
183 
valid_tag(config_key_type name)184 bool config::valid_tag(config_key_type name)
185 {
186 	if(name == "") {
187 		// Empty strings not allowed
188 		return false;
189 	} else if(name == "_") {
190 		// A lone underscore isn't a valid tag name
191 		return false;
192 	} else {
193 		return std::all_of(name.begin(), name.end(), [](const char& c)
194 		{
195 			// Only alphanumeric ASCII characters and underscores are allowed
196 			return std::isalnum(c, std::locale::classic()) || c == '_';
197 		});
198 	}
199 }
200 
valid_attribute(config_key_type name)201 bool config::valid_attribute(config_key_type name)
202 {
203 	if(name.empty()) {
204 		return false;
205 	}
206 
207 	for(char c : name) {
208 		if(!std::isalnum(c, std::locale::classic()) && c != '_') {
209 			return false;
210 		}
211 	}
212 
213 	return true;
214 }
215 
has_attribute(config_key_type key) const216 bool config::has_attribute(config_key_type key) const
217 {
218 	check_valid();
219 	return values_.find(key) != values_.end();
220 }
221 
has_old_attribute(config_key_type key,const std::string & old_key,const std::string & msg) const222 bool config::has_old_attribute(config_key_type key, const std::string& old_key, const std::string& msg) const
223 {
224 	check_valid();
225 	if(values_.find(key) != values_.end()) {
226 		return true;
227 	} else if(values_.find(old_key) != values_.end()) {
228 		if(!msg.empty()) {
229 			lg::wml_error() << msg;
230 		}
231 
232 		return true;
233 	}
234 
235 	return false;
236 }
237 
remove_attribute(config_key_type key)238 void config::remove_attribute(config_key_type key)
239 {
240 	check_valid();
241 	map_erase_key(values_, key);
242 }
243 
append_children(const config & cfg)244 void config::append_children(const config& cfg)
245 {
246 	check_valid(cfg);
247 
248 	for(const any_child& value : cfg.all_children_range()) {
249 		add_child(value.key, value.cfg);
250 	}
251 }
252 
append_children(config && cfg)253 void config::append_children(config&& cfg)
254 {
255 	check_valid(cfg);
256 
257 #if 0
258 	//For some unknown reason this doesn't compile.
259 	if(children_.empty()) {
260 		//optimisation
261 		children_ = std::move(cfg.children_);
262 		ordered_children = std::move(cfg.ordered_children);
263 		cfg.clear_all_children();
264 		return;
265 	}
266 #endif
267 	for(const any_child& value : cfg.all_children_range()) {
268 		add_child(value.key, std::move(value.cfg));
269 	}
270 	cfg.clear_all_children();
271 }
272 
append_attributes(const config & cfg)273 void config::append_attributes(const config& cfg)
274 {
275 	check_valid(cfg);
276 	for(const attribute& v : cfg.values_) {
277 		values_[v.first] = v.second;
278 	}
279 }
280 
append_children(const config & cfg,const std::string & key)281 void config::append_children(const config& cfg, const std::string& key)
282 {
283 	check_valid(cfg);
284 
285 	for(const config& value : cfg.child_range(key)) {
286 		add_child(key, value);
287 	}
288 }
289 
append(const config & cfg)290 void config::append(const config& cfg)
291 {
292 	append_children(cfg);
293 	for(const attribute& v : cfg.values_) {
294 		values_[v.first] = v.second;
295 	}
296 }
297 
append(config && cfg)298 void config::append(config&& cfg)
299 {
300 	append_children(std::move(cfg));
301 
302 	if(values_.empty()) {
303 		//optimisation.
304 		values_ = std::move(cfg.values_);
305 	}
306 	else {
307 		for(const attribute& v : cfg.values_) {
308 			//TODO: move the attributes as well?
309 			values_[v.first] = v.second;
310 		}
311 	}
312 	cfg.clear_attributes();
313 }
314 
append_children_by_move(config & cfg,const std::string & key)315 void config::append_children_by_move(config& cfg, const std::string& key)
316 {
317 	check_valid(cfg);
318 
319 	// DO note this leaves the tags empty in the source config. Not sure if
320 	// that should be changed.
321 	for(config& value : cfg.child_range(key)) {
322 		add_child(key, std::move(value));
323 	}
324 
325 	cfg.clear_children_impl(key);
326 }
327 
merge_children(const std::string & key)328 void config::merge_children(const std::string& key)
329 {
330 	check_valid();
331 
332 	if(child_count(key) < 2) {
333 		return;
334 	}
335 
336 	config merged_children;
337 	for(config& cfg : child_range(key)) {
338 		merged_children.append(std::move(cfg));
339 	}
340 
341 	clear_children_impl(key);
342 	add_child(key, std::move(merged_children));
343 }
344 
merge_children_by_attribute(const std::string & key,const std::string & attribute)345 void config::merge_children_by_attribute(const std::string& key, const std::string& attribute)
346 {
347 	check_valid();
348 
349 	if(child_count(key) < 2) {
350 		return;
351 	}
352 
353 	typedef std::map<std::string, config> config_map;
354 	config_map merged_children_map;
355 	for(config& cfg : child_range(key)) {
356 		merged_children_map[cfg[attribute]].append(std::move(cfg));
357 	}
358 
359 	clear_children_impl(key);
360 	for(const config_map::value_type& i : merged_children_map) {
361 		add_child(key, i.second); // TODO: can we use std::move?
362 	}
363 }
364 
child_range(config_key_type key)365 config::child_itors config::child_range(config_key_type key)
366 {
367 	check_valid();
368 
369 	child_map::iterator i = children_.find(key);
370 	static child_list dummy;
371 	child_list* p = &dummy;
372 	if(i != children_.end()) {
373 		p = &i->second;
374 	}
375 
376 	return child_itors(child_iterator(p->begin()), child_iterator(p->end()));
377 }
378 
child_range(config_key_type key) const379 config::const_child_itors config::child_range(config_key_type key) const
380 {
381 	check_valid();
382 
383 	child_map::const_iterator i = children_.find(key);
384 	static child_list dummy;
385 	const child_list* p = &dummy;
386 	if(i != children_.end()) {
387 		p = &i->second;
388 	}
389 
390 	return const_child_itors(const_child_iterator(p->begin()), const_child_iterator(p->end()));
391 }
392 
child_count(config_key_type key) const393 unsigned config::child_count(config_key_type key) const
394 {
395 	check_valid();
396 
397 	child_map::const_iterator i = children_.find(key);
398 	if(i != children_.end()) {
399 		return i->second.size();
400 	}
401 
402 	return 0;
403 }
404 
all_children_count() const405 unsigned config::all_children_count() const
406 {
407 	return ordered_children.size();
408 }
409 
attribute_count() const410 unsigned config::attribute_count() const
411 {
412 	return std::count_if(values_.begin(), values_.end(), [](const attribute& v) { return !v.second.blank(); });
413 }
414 
has_child(config_key_type key) const415 bool config::has_child(config_key_type key) const
416 {
417 	check_valid();
418 
419 	return children_.find(key) != children_.end();
420 }
421 
child(config_key_type key,int n)422 config& config::child(config_key_type key, int n)
423 {
424 	check_valid();
425 
426 	const child_map::const_iterator i = children_.find(key);
427 	if(i == children_.end()) {
428 		DBG_CF << "The config object has no child named »" << key << "«.\n";
429 
430 		return invalid;
431 	}
432 
433 	if(n < 0)
434 		n = i->second.size() + n;
435 	if(size_t(n) < i->second.size()) {
436 		return *i->second[n];
437 	} else {
438 		DBG_CF << "The config object has only »" << i->second.size() << "« children named »" << key
439 			   << "«; request for the index »" << n << "« cannot be honored.\n";
440 
441 		return invalid;
442 	}
443 }
444 
child(config_key_type key,const std::string & parent)445 config& config::child(config_key_type key, const std::string& parent)
446 {
447 	return config_implementation::child(this, key, parent);
448 }
449 
child(config_key_type key,const std::string & parent) const450 const config& config::child(config_key_type key, const std::string& parent) const
451 {
452 	return config_implementation::child(this, key, parent);
453 }
454 
child_or_empty(config_key_type key) const455 const config& config::child_or_empty(config_key_type key) const
456 {
457 	static const config empty_cfg;
458 	check_valid();
459 
460 	child_map::const_iterator i = children_.find(key);
461 	if(i != children_.end() && !i->second.empty()) {
462 		return *i->second.front();
463 	}
464 
465 	return empty_cfg;
466 }
467 
child_or_add(config_key_type key)468 config& config::child_or_add(config_key_type key)
469 {
470 	child_map::const_iterator i = children_.find(key);
471 	if(i != children_.end() && !i->second.empty()) {
472 		return *i->second.front();
473 	}
474 
475 	return add_child(key);
476 }
477 
add_child(config_key_type key)478 config& config::add_child(config_key_type key)
479 {
480 	check_valid();
481 
482 	child_list& v = map_get(children_, key);
483 	v.emplace_back(new config());
484 	ordered_children.emplace_back(children_.find(key), v.size() - 1);
485 	return *v.back();
486 }
487 
add_child(config_key_type key,const config & val)488 config& config::add_child(config_key_type key, const config& val)
489 {
490 	check_valid(val);
491 
492 	child_list& v = map_get(children_, key);
493 	v.emplace_back(new config(val));
494 	ordered_children.emplace_back(children_.find(key), v.size() - 1);
495 
496 	return *v.back();
497 }
498 
add_child(config_key_type key,config && val)499 config& config::add_child(config_key_type key, config&& val)
500 {
501 	check_valid(val);
502 
503 	child_list& v = map_get(children_, key);
504 	v.emplace_back(new config(std::move(val)));
505 	ordered_children.emplace_back(children_.find(key), v.size() - 1);
506 
507 	return *v.back();
508 }
509 
add_child_at(config_key_type key,const config & val,unsigned index)510 config& config::add_child_at(config_key_type key, const config& val, unsigned index)
511 {
512 	check_valid(val);
513 
514 	child_list& v = map_get(children_, key);
515 	if(index > v.size()) {
516 		throw error("illegal index to add child at");
517 	}
518 
519 	v.emplace(v.begin() + index, new config(val));
520 
521 	bool inserted = false;
522 
523 	const child_pos value(children_.find(key), index);
524 
525 	std::vector<child_pos>::iterator ord = ordered_children.begin();
526 	for(; ord != ordered_children.end(); ++ord) {
527 		if(ord->pos != value.pos)
528 			continue;
529 		if(!inserted && ord->index == index) {
530 			ord = ordered_children.insert(ord, value);
531 			inserted = true;
532 		} else if(ord->index >= index) {
533 			ord->index++;
534 		}
535 	}
536 
537 	if(!inserted) {
538 		ordered_children.push_back(value);
539 	}
540 
541 	return *v[index];
542 }
543 
544 namespace
545 {
546 struct remove_ordered
547 {
remove_ordered__anon13feaf990411::remove_ordered548 	remove_ordered(const config::child_map::iterator& iter)
549 		: iter_(iter)
550 	{
551 	}
552 
operator ()__anon13feaf990411::remove_ordered553 	bool operator()(const config::child_pos& pos) const
554 	{
555 		return pos.pos == iter_;
556 	}
557 
558 private:
559 	config::child_map::iterator iter_;
560 };
561 } // end anon namespace
562 
clear_children_impl(config_key_type key)563 void config::clear_children_impl(config_key_type key)
564 {
565 	check_valid();
566 
567 	child_map::iterator i = children_.find(key);
568 	if(i == children_.end())
569 		return;
570 
571 	ordered_children.erase(
572 		std::remove_if(ordered_children.begin(), ordered_children.end(), remove_ordered(i)),
573 		ordered_children.end());
574 
575 	children_.erase(i);
576 }
577 
splice_children(config & src,const std::string & key)578 void config::splice_children(config& src, const std::string& key)
579 {
580 	check_valid(src);
581 
582 	child_map::iterator i_src = src.children_.find(key);
583 	if(i_src == src.children_.end()) {
584 		return;
585 	}
586 
587 	src.ordered_children.erase(
588 		std::remove_if(src.ordered_children.begin(), src.ordered_children.end(), remove_ordered(i_src)),
589 		src.ordered_children.end());
590 
591 	child_list& dst = map_get(children_, key);
592 	child_map::iterator i_dst = children_.find(key);
593 
594 	unsigned before = dst.size();
595 	dst.insert(dst.end(), std::make_move_iterator(i_src->second.begin()), std::make_move_iterator(i_src->second.end()));
596 	src.children_.erase(i_src);
597 	// key might be a reference to i_src->first, so it is no longer usable.
598 
599 	for(unsigned j = before; j < dst.size(); ++j) {
600 		ordered_children.emplace_back(i_dst, j);
601 	}
602 }
603 
recursive_clear_value(config_key_type key)604 void config::recursive_clear_value(config_key_type key)
605 {
606 	check_valid();
607 
608 	map_erase_key(values_, key);
609 
610 	for(std::pair<const std::string, child_list>& p : children_) {
611 		for(auto& cfg : p.second) {
612 			cfg->recursive_clear_value(key);
613 		}
614 	}
615 }
616 
remove_child(const child_map::iterator & pos,unsigned index)617 std::vector<config::child_pos>::iterator config::remove_child(const child_map::iterator& pos, unsigned index)
618 {
619 	/* Find the position with the correct index and decrement all the
620 	   indices in the ordering that are above this index. */
621 	unsigned found = 0;
622 	for(child_pos& p : ordered_children) {
623 		if(p.pos != pos) {
624 			continue;
625 		}
626 
627 		if(p.index == index) {
628 			found = &p - &ordered_children.front();
629 		} else if(p.index > index) {
630 			--p.index;
631 		}
632 	}
633 
634 	// Remove from the child map.
635 	pos->second.erase(pos->second.begin() + index);
636 
637 	// Erase from the ordering and return the next position.
638 	return ordered_children.erase(ordered_children.begin() + found);
639 }
640 
erase(const config::all_children_iterator & i)641 config::all_children_iterator config::erase(const config::all_children_iterator& i)
642 {
643 	return all_children_iterator(remove_child(i.i_->pos, i.i_->index));
644 }
645 
remove_child(config_key_type key,unsigned index)646 void config::remove_child(config_key_type key, unsigned index)
647 {
648 	check_valid();
649 
650 	child_map::iterator i = children_.find(key);
651 	if(i == children_.end() || index >= i->second.size()) {
652 		ERR_CF << "Error: attempting to delete non-existing child: " << key << "[" << index << "]\n";
653 		return;
654 	}
655 
656 	remove_child(i, index);
657 }
658 
remove_children(config_key_type key,std::function<bool (const config &)> p)659 void config::remove_children(config_key_type key, std::function<bool(const config&)> p)
660 {
661 	check_valid();
662 
663 	child_map::iterator pos = children_.find(key);
664 	if(pos == children_.end()) {
665 		return;
666 	}
667 
668 	const auto predicate = [p](const std::unique_ptr<config>& child)
669 	{
670 		return p(*child);
671 	};
672 
673 	auto child_it = std::find_if(pos->second.begin(), pos->second.end(), predicate);
674 	while(child_it != pos->second.end()) {
675 		unsigned index = std::distance(pos->second.begin(), child_it);
676 		remove_child(pos, index);
677 		child_it = std::find_if(pos->second.begin() + index, pos->second.end(), predicate);
678 	}
679 }
680 
operator [](config_key_type key) const681 const config::attribute_value& config::operator[](config_key_type key) const
682 {
683 	check_valid();
684 
685 	const attribute_map::const_iterator i = values_.find(key);
686 	if(i != values_.end()) {
687 		return i->second;
688 	}
689 
690 	static const attribute_value empty_attribute;
691 	return empty_attribute;
692 }
693 
get(config_key_type key) const694 const config::attribute_value* config::get(config_key_type key) const
695 {
696 	check_valid();
697 	attribute_map::const_iterator i = values_.find(key);
698 	return i != values_.end() ? &i->second : nullptr;
699 }
700 
operator [](config_key_type key)701 config::attribute_value& config::operator[](config_key_type key)
702 {
703 	check_valid();
704 
705 	auto res = values_.lower_bound(key);
706 
707 	if(res == values_.end() || key != res->first) {
708 		res = values_.emplace_hint(res, std::piecewise_construct, std::forward_as_tuple(key), std::tuple<>());
709 	}
710 
711 	return res->second;
712 }
713 
get_old_attribute(config_key_type key,const std::string & old_key,const std::string & in_tag) const714 const config::attribute_value& config::get_old_attribute(
715 		config_key_type key, const std::string& old_key, const std::string& in_tag) const
716 {
717 	check_valid();
718 
719 	attribute_map::const_iterator i = values_.find(key);
720 	if(i != values_.end()) {
721 		return i->second;
722 	}
723 
724 	i = values_.find(old_key);
725 	if(i != values_.end()) {
726 		if(!in_tag.empty()) {
727 			const std::string what = formatter() << "[" << in_tag << "]" << old_key << "=";
728 			const std::string msg  = formatter() << "Use " << key << "= instead.";
729 			deprecated_message(what, DEP_LEVEL::INDEFINITE, "", msg);
730 			lg::wml_error() << msg;
731 		}
732 
733 		return i->second;
734 	}
735 
736 	static const attribute_value empty_attribute;
737 	return empty_attribute;
738 }
739 
merge_attributes(const config & cfg)740 void config::merge_attributes(const config& cfg)
741 {
742 	check_valid(cfg);
743 
744 	assert(this != &cfg);
745 	for(const attribute& v : cfg.values_) {
746 		std::string key = v.first;
747 		if(key.substr(0, 7) == "add_to_") {
748 			std::string add_to = key.substr(7);
749 			values_[add_to] = values_[add_to].to_double() + v.second.to_double();
750 		} else if(key.substr(0, 10) == "concat_to_") {
751 			std::string concat_to = key.substr(10);
752 			// TODO: Only use t_string if one or both are actually translatable?
753 			// That probably requires using a visitor though.
754 			values_[concat_to] = values_[concat_to].t_str() + v.second.t_str();
755 		} else {
756 			values_[v.first] = v.second;
757 		}
758 	}
759 }
760 
attribute_range() const761 config::const_attr_itors config::attribute_range() const
762 {
763 	check_valid();
764 
765 	const_attr_itors range(const_attribute_iterator(values_.begin()), const_attribute_iterator(values_.end()));
766 
767 	// Ensure the first element is not blank, as a few places assume this
768 	while(range.begin() != range.end() && range.begin()->second.blank()) {
769 		range.pop_front();
770 	}
771 
772 	return range;
773 }
774 
attribute_range()775 config::attr_itors config::attribute_range()
776 {
777 	check_valid();
778 	attr_itors range(attribute_iterator(values_.begin()), attribute_iterator(values_.end()));
779 
780 	// Ensure the first element is not blank, as a few places assume this
781 	while(range.begin() != range.end() && range.begin()->second.blank()) {
782 		range.pop_front();
783 	}
784 
785 	return range;
786 }
787 
find_child(config_key_type key,const std::string & name,const std::string & value)788 config& config::find_child(config_key_type key, const std::string& name, const std::string& value)
789 {
790 	check_valid();
791 
792 	const child_map::iterator i = children_.find(key);
793 	if(i == children_.end()) {
794 		DBG_CF << "Key »" << name << "« value »" << value << "« pair not found as child of key »" << key << "«.\n";
795 
796 		return invalid;
797 	}
798 
799 	const child_list::iterator j = std::find_if(i->second.begin(), i->second.end(),
800 		[&](const std::unique_ptr<config>& pcfg) {
801 			const config& cfg = *pcfg;
802 			return cfg[name] == value;
803 		}
804 	);
805 
806 	if(j != i->second.end()) {
807 		return **j;
808 	}
809 
810 	DBG_CF << "Key »" << name << "« value »" << value << "« pair not found as child of key »" << key << "«.\n";
811 
812 	return invalid;
813 }
814 
clear()815 void config::clear()
816 {
817 	// No validity check for this function.
818 	children_.clear();
819 	values_.clear();
820 	ordered_children.clear();
821 }
822 
clear_all_children()823 void config::clear_all_children()
824 {
825 	// No validity check for this function.
826 	children_.clear();
827 	ordered_children.clear();
828 }
829 
clear_attributes()830 void config::clear_attributes()
831 {
832 	// No validity check for this function.
833 	values_.clear();
834 }
835 
empty() const836 bool config::empty() const
837 {
838 	check_valid();
839 
840 	return children_.empty() && values_.empty();
841 }
842 
operator *() const843 config::all_children_iterator::reference config::all_children_iterator::operator*() const
844 {
845 	return any_child(&i_->pos->first, i_->pos->second[i_->index].get());
846 }
847 
operator *() const848 config::const_all_children_iterator::reference config::const_all_children_iterator::operator*() const
849 {
850 	return any_child(&i_->pos->first, i_->pos->second[i_->index].get());
851 }
852 
ordered_begin() const853 config::const_all_children_iterator config::ordered_begin() const
854 {
855 	return const_all_children_iterator(ordered_children.cbegin());
856 }
857 
ordered_cbegin() const858 config::const_all_children_iterator config::ordered_cbegin() const
859 {
860 	return const_all_children_iterator(ordered_children.cbegin());
861 }
862 
ordered_end() const863 config::const_all_children_iterator config::ordered_end() const
864 {
865 	return const_all_children_iterator(ordered_children.cend());
866 }
867 
ordered_cend() const868 config::const_all_children_iterator config::ordered_cend() const
869 {
870 	return const_all_children_iterator(ordered_children.cend());
871 }
872 
all_children_range() const873 config::const_all_children_itors config::all_children_range() const
874 {
875 	return const_all_children_itors(
876 		const_all_children_iterator(ordered_children.cbegin()),
877 		const_all_children_iterator(ordered_children.cend())
878 	);
879 }
880 
ordered_begin()881 config::all_children_iterator config::ordered_begin()
882 {
883 	return all_children_iterator(ordered_children.begin());
884 }
885 
ordered_end()886 config::all_children_iterator config::ordered_end()
887 {
888 	return all_children_iterator(ordered_children.end());
889 }
890 
all_children_range()891 config::all_children_itors config::all_children_range()
892 {
893 	return all_children_itors(
894 		all_children_iterator(ordered_children.begin()),
895 		all_children_iterator(ordered_children.end())
896 	);
897 }
898 
get_diff(const config & c) const899 config config::get_diff(const config& c) const
900 {
901 	check_valid(c);
902 
903 	config res;
904 	get_diff(c, res);
905 	return res;
906 }
907 
get_diff(const config & c,config & res) const908 void config::get_diff(const config& c, config& res) const
909 {
910 	check_valid(c);
911 	check_valid(res);
912 
913 	config* inserts = nullptr;
914 
915 	for(const auto& v : values_) {
916 		if(v.second.blank()) {
917 			continue;
918 		}
919 
920 		const attribute_map::const_iterator j = c.values_.find(v.first);
921 		if(j == c.values_.end() || (v.second != j->second && !v.second.blank())) {
922 			if(inserts == nullptr) {
923 				inserts = &res.add_child("insert");
924 			}
925 
926 			(*inserts)[v.first] = v.second;
927 		}
928 	}
929 
930 	config* deletes = nullptr;
931 
932 	for(const auto& v : c.values_) {
933 		if(v.second.blank()) {
934 			continue;
935 		}
936 
937 		const attribute_map::const_iterator itor = values_.find(v.first);
938 		if(itor == values_.end() || itor->second.blank()) {
939 			if(deletes == nullptr) {
940 				deletes = &res.add_child("delete");
941 			}
942 
943 			(*deletes)[v.first] = "x";
944 		}
945 	}
946 
947 	std::vector<std::string> entities;
948 
949 	for(const auto& child : children_) {
950 		entities.push_back(child.first);
951 	}
952 
953 	for(const auto& child : c.children_) {
954 		if(children_.count(child.first) == 0) {
955 			entities.push_back(child.first);
956 		}
957 	}
958 
959 	for(const std::string& entity : entities) {
960 		const child_map::const_iterator itor_a = children_.find(entity);
961 		const child_map::const_iterator itor_b = c.children_.find(entity);
962 
963 		static const child_list dummy;
964 
965 		// Get the two child lists. 'b' has to be modified to look like 'a'.
966 		const child_list& a = itor_a != children_.end() ? itor_a->second : dummy;
967 		const child_list& b = itor_b != c.children_.end() ? itor_b->second : dummy;
968 
969 		size_t ndeletes = 0;
970 		size_t ai = 0, bi = 0;
971 		while(ai != a.size() || bi != b.size()) {
972 			// If the two elements are the same, nothing needs to be done.
973 			if(ai < a.size() && bi < b.size() && *a[ai] == *b[bi]) {
974 				++ai;
975 				++bi;
976 			} else {
977 				// We have to work out what the most appropriate operation --
978 				// delete, insert, or change is the best to get b[bi] looking like a[ai].
979 				std::stringstream buf;
980 
981 				// If b has more elements than a, then we assume this element
982 				// is an element that needs deleting.
983 				if(b.size() - bi > a.size() - ai) {
984 					config& new_delete = res.add_child("delete_child");
985 					buf << bi - ndeletes;
986 					new_delete.values_["index"] = buf.str();
987 					new_delete.add_child(entity);
988 
989 					++ndeletes;
990 					++bi;
991 				}
992 
993 				// If b has less elements than a, then we assume this element
994 				// is an element that needs inserting.
995 				else if(b.size() - bi < a.size() - ai) {
996 					config& new_insert = res.add_child("insert_child");
997 					buf << ai;
998 					new_insert.values_["index"] = buf.str();
999 					new_insert.add_child(entity, *a[ai]);
1000 
1001 					++ai;
1002 				}
1003 
1004 				// Otherwise, they have the same number of elements,
1005 				// so try just changing this element to match.
1006 				else {
1007 					config& new_change = res.add_child("change_child");
1008 					buf << bi;
1009 					new_change.values_["index"] = buf.str();
1010 					new_change.add_child(entity, a[ai]->get_diff(*b[bi]));
1011 
1012 					++ai;
1013 					++bi;
1014 				}
1015 			}
1016 		}
1017 	}
1018 }
1019 
apply_diff(const config & diff,bool track)1020 void config::apply_diff(const config& diff, bool track /* = false */)
1021 {
1022 	check_valid(diff);
1023 
1024 	if(track) {
1025 		values_[diff_track_attribute] = "modified";
1026 	}
1027 
1028 	if(const config& inserts = diff.child("insert")) {
1029 		for(const attribute& v : inserts.attribute_range()) {
1030 			values_[v.first] = v.second;
1031 		}
1032 	}
1033 
1034 	if(const config& deletes = diff.child("delete")) {
1035 		for(const attribute& v : deletes.attribute_range()) {
1036 			values_.erase(v.first);
1037 		}
1038 	}
1039 
1040 	for(const config& i : diff.child_range("change_child")) {
1041 		const size_t index = lexical_cast<size_t>(i["index"].str());
1042 		for(const any_child& item : i.all_children_range()) {
1043 			if(item.key.empty()) {
1044 				continue;
1045 			}
1046 
1047 			const child_map::iterator itor = children_.find(item.key);
1048 			if(itor == children_.end() || index >= itor->second.size()) {
1049 				throw error("error in diff: could not find element '" + item.key + "'");
1050 			}
1051 
1052 			itor->second[index]->apply_diff(item.cfg, track);
1053 		}
1054 	}
1055 
1056 	for(const config& i : diff.child_range("insert_child")) {
1057 		const size_t index = lexical_cast<size_t>(i["index"].str());
1058 		for(const any_child& item : i.all_children_range()) {
1059 			config& inserted = add_child_at(item.key, item.cfg, index);
1060 			if(track) {
1061 				inserted[diff_track_attribute] = "new";
1062 			}
1063 		}
1064 	}
1065 
1066 	for(const config& i : diff.child_range("delete_child")) {
1067 		const size_t index = lexical_cast<size_t>(i["index"].str());
1068 		for(const any_child& item : i.all_children_range()) {
1069 			if(!track) {
1070 				remove_child(item.key, index);
1071 			} else {
1072 				const child_map::iterator itor = children_.find(item.key);
1073 				if(itor == children_.end() || index >= itor->second.size()) {
1074 					throw error("error in diff: could not find element '" + item.key + "'");
1075 				}
1076 
1077 				itor->second[index]->values_[diff_track_attribute] = "deleted";
1078 			}
1079 		}
1080 	}
1081 }
1082 
clear_diff_track(const config & diff)1083 void config::clear_diff_track(const config& diff)
1084 {
1085 	remove_attribute(diff_track_attribute);
1086 	for(const config& i : diff.child_range("delete_child")) {
1087 		const size_t index = lexical_cast<size_t>(i["index"].str());
1088 		for(const any_child& item : i.all_children_range()) {
1089 			remove_child(item.key, index);
1090 		}
1091 	}
1092 
1093 	for(const config& i : diff.child_range("change_child")) {
1094 		const size_t index = lexical_cast<size_t>(i["index"].str());
1095 		for(const any_child& item : i.all_children_range()) {
1096 			if(item.key.empty()) {
1097 				continue;
1098 			}
1099 
1100 			const child_map::iterator itor = children_.find(item.key);
1101 			if(itor == children_.end() || index >= itor->second.size()) {
1102 				throw error("error in diff: could not find element '" + item.key + "'");
1103 			}
1104 
1105 			itor->second[index]->clear_diff_track(item.cfg);
1106 		}
1107 	}
1108 
1109 	for(std::pair<const std::string, child_list>& p : children_) {
1110 		for(auto& cfg : p.second) {
1111 			cfg->remove_attribute(diff_track_attribute);
1112 		}
1113 	}
1114 }
1115 
1116 /**
1117  * Merge config 'c' into this config, overwriting this config's values.
1118  */
merge_with(const config & c)1119 void config::merge_with(const config& c)
1120 {
1121 	check_valid(c);
1122 
1123 	std::vector<child_pos> to_remove;
1124 	std::map<std::string, unsigned> visitations;
1125 
1126 	// Merge attributes first
1127 	merge_attributes(c);
1128 
1129 	// Now merge shared tags
1130 	all_children_iterator::Itor i, i_end = ordered_children.end();
1131 	for(i = ordered_children.begin(); i != i_end; ++i) {
1132 		const std::string& tag = i->pos->first;
1133 		const child_map::const_iterator j = c.children_.find(tag);
1134 
1135 		if(j != c.children_.end()) {
1136 			unsigned& visits = visitations[tag];
1137 
1138 			if(visits < j->second.size()) {
1139 				// Get a const config so we do not add attributes.
1140 				const config& merge_child = *j->second[visits++];
1141 
1142 				if(merge_child["__remove"].to_bool()) {
1143 					to_remove.push_back(*i);
1144 				} else {
1145 					(i->pos->second[i->index])->merge_with(merge_child);
1146 				}
1147 			}
1148 		}
1149 	}
1150 
1151 	// Now add any unvisited tags
1152 	for(const auto& pair : c.children_) {
1153 		const std::string& tag = pair.first;
1154 		unsigned& visits = visitations[tag];
1155 		while(visits < pair.second.size()) {
1156 			add_child(tag, *pair.second[visits++]);
1157 		}
1158 	}
1159 
1160 	// Remove those marked so
1161 	std::map<std::string, unsigned> removals;
1162 	for(const child_pos& pos : to_remove) {
1163 		const std::string& tag = pos.pos->first;
1164 		unsigned& removes = removals[tag];
1165 		remove_child(tag, pos.index - removes++);
1166 	}
1167 }
1168 
1169 /**
1170  * Merge config 'c' into this config, preserving this config's values.
1171  */
inherit_from(const config & c)1172 void config::inherit_from(const config& c)
1173 {
1174 	// Using a scratch config and merge_with() seems to execute about as fast
1175 	// as direct coding of this merge.
1176 	config scratch(c);
1177 	scratch.merge_with(*this);
1178 	swap(scratch);
1179 }
1180 
matches(const config & filter) const1181 bool config::matches(const config& filter) const
1182 {
1183 	check_valid(filter);
1184 
1185 	for(const attribute& i : filter.attribute_range()) {
1186 		const attribute_value* v = get(i.first);
1187 		if(!v || *v != i.second) {
1188 			return false;
1189 		}
1190 	}
1191 
1192 	for(const any_child& i : filter.all_children_range()) {
1193 		if(i.key == "not") {
1194 			if(matches(i.cfg)) {
1195 				return false;
1196 			}
1197 
1198 			continue;
1199 		}
1200 
1201 		bool found = false;
1202 		for(const config& j : child_range(i.key)) {
1203 			if(j.matches(i.cfg)) {
1204 				found = true;
1205 				break;
1206 			}
1207 		}
1208 
1209 		if(!found) {
1210 			return false;
1211 		}
1212 	}
1213 
1214 	return true;
1215 }
1216 
debug() const1217 std::string config::debug() const
1218 {
1219 	check_valid();
1220 
1221 	std::ostringstream outstream;
1222 	outstream << *this;
1223 	return outstream.str();
1224 }
1225 
operator <<(std::ostream & outstream,const config & cfg)1226 std::ostream& operator<<(std::ostream& outstream, const config& cfg)
1227 {
1228 	static int i = 0;
1229 	i++;
1230 
1231 	for(const config::attribute& val : cfg.attribute_range()) {
1232 		if(val.second.blank()) {
1233 			continue;
1234 		}
1235 
1236 		for(int j = 0; j < i - 1; j++) {
1237 			outstream << '\t';
1238 		}
1239 
1240 		outstream << val.first << " = " << val.second << '\n';
1241 	}
1242 
1243 	for(const config::any_child& child : cfg.all_children_range()) {
1244 		for(int j = 0; j < i - 1; ++j) {
1245 			outstream << '\t';
1246 		}
1247 
1248 		outstream << "[" << child.key << "]\n";
1249 		outstream << child.cfg;
1250 
1251 		for(int j = 0; j < i - 1; ++j) {
1252 			outstream << '\t';
1253 		}
1254 
1255 		outstream << "[/" << child.key << "]\n";
1256 	}
1257 
1258 	i--;
1259 	return outstream;
1260 }
1261 
hash() const1262 std::string config::hash() const
1263 {
1264 	check_valid();
1265 
1266 	static const unsigned int hash_length = 128;
1267 	static const char hash_string[] = "+-,.<>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1268 	char hash_str[hash_length + 1];
1269 
1270 	unsigned int i;
1271 	for(i = 0; i != hash_length; ++i) {
1272 		hash_str[i] = 'a';
1273 	}
1274 
1275 	hash_str[hash_length] = 0;
1276 
1277 	i = 0;
1278 	for(const attribute& val : values_) {
1279 		if(val.second.blank()) {
1280 			continue;
1281 		}
1282 
1283 		for(char c : val.first) {
1284 			hash_str[i] ^= c;
1285 			if(++i == hash_length) {
1286 				i = 0;
1287 			}
1288 		}
1289 
1290 		std::string base_str = val.second.t_str().base_str();
1291 		for(const char c : base_str) {
1292 			hash_str[i] ^= c;
1293 			if(++i == hash_length) {
1294 				i = 0;
1295 			}
1296 		}
1297 	}
1298 
1299 	for(const any_child& ch : all_children_range()) {
1300 		std::string child_hash = ch.cfg.hash();
1301 		for(char c : child_hash) {
1302 			hash_str[i] ^= c;
1303 			++i;
1304 			if(i == hash_length) {
1305 				i = 0;
1306 			}
1307 		}
1308 	}
1309 
1310 	for(i = 0; i != hash_length; ++i) {
1311 		hash_str[i] = hash_string[static_cast<unsigned>(hash_str[i]) % strlen(hash_string)];
1312 	}
1313 
1314 	return std::string(hash_str);
1315 }
1316 
swap(config & cfg)1317 void config::swap(config& cfg)
1318 {
1319 	check_valid(cfg);
1320 
1321 	values_.swap(cfg.values_);
1322 	children_.swap(cfg.children_);
1323 	ordered_children.swap(cfg.ordered_children);
1324 }
1325 
swap(config & lhs,config & rhs)1326 void swap(config& lhs, config& rhs)
1327 {
1328 	lhs.swap(rhs);
1329 }
1330 
validate_wml() const1331 bool config::validate_wml() const
1332 {
1333 	return std::all_of(children_.begin(), children_.end(), [](const child_map::value_type& pair)
1334 	{
1335 		return valid_tag(pair.first) &&
1336 			std::all_of(pair.second.begin(), pair.second.end(),
1337 			[](const std::unique_ptr<config>& c) { return c->validate_wml(); });
1338 	});
1339 }
1340 
operator ==(const config & a,const config & b)1341 bool operator==(const config& a, const config& b)
1342 {
1343 	a.check_valid(b);
1344 
1345 	if(a.values_ != b.values_) {
1346 		return false;
1347 	}
1348 
1349 	config::const_all_children_itors x = a.all_children_range(), y = b.all_children_range();
1350 	for(; !x.empty() && !y.empty(); x.pop_front(), y.pop_front()) {
1351 		if(x.front().key != y.front().key || x.front().cfg != y.front().cfg) {
1352 			return false;
1353 		}
1354 	}
1355 
1356 	return x.empty() && y.empty();
1357 }
1358