File: DefinitionTag.cpp

package info (click to toggle)
spring 106.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 55,316 kB
  • sloc: cpp: 543,954; ansic: 44,800; python: 12,575; java: 12,201; awk: 5,889; sh: 1,796; asm: 1,546; xml: 655; perl: 405; php: 211; objc: 194; makefile: 76; sed: 2
file content (254 lines) | stat: -rw-r--r-- 6,362 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */

#include "DefinitionTag.h"
#include "System/Log/ILog.h"
#include "System/StringUtil.h"
#include <iostream>
#ifndef _MSC_VER
#include <cxxabi.h>
#endif

using std::cout;


/**
 * @brief Log an error about a DefTagMetaData
 */
#define LOG_VAR(data, fmt, ...) \
	LOG_L(L_ERROR, "%s:%d: " fmt, (data)->GetDeclarationFile().Get().c_str(), (data)->GetDeclarationLine().Get(), ## __VA_ARGS__) \


DefType::DefType(const char* n): name(n) {
	metaDataMem.fill(0);
	defInitFuncs.fill(nullptr);
	tagMetaData.fill(nullptr);
	GetTypes().push_back(this);
}


void DefType::AddTagMetaData(const DefTagMetaData* data)
{
	const auto key = data->GetInternalName();

	const auto tend = tagMetaData.begin() + tagMetaDataCnt;
	const auto pred = [&](const DefTagMetaData* md) { return (key == md->GetInternalName()); };
	const auto iter = std::find_if(tagMetaData.begin(), tend, pred);

	if (iter != tend) {
		LOG_VAR(data, "Duplicate config variable declaration \"%s\"", key.c_str());
		LOG_VAR(*iter, "  Previously declared here");
		assert(false);
		return;
	}
	if (tagMetaDataCnt >= tagMetaData.size()) {
		LOG_VAR(data, "Too many config-variable metadata instances");
		return;
	}

	tagMetaData[tagMetaDataCnt++] = data;
}


const DefTagMetaData* DefType::GetMetaDataByInternalKey(const string& key)
{
	const auto tend = tagMetaData.begin() + tagMetaDataCnt;
	const auto pred = [&](const DefTagMetaData* md) { return (key == md->GetInternalName()); };
	const auto iter = std::find_if(tagMetaData.begin(), tend, pred);

	return ((iter == tend)? nullptr: *iter);
}


const DefTagMetaData* DefType::GetMetaDataByExternalKey(const string& key)
{
	const std::string lkey = StringToLower(key);

	for (unsigned int i = 0; i < tagMetaDataCnt; i++) {
		const DefTagMetaData* md = tagMetaData[i];

		if (md->GetExternalName().IsSet()) {
			if (lkey == StringToLower(md->GetExternalName().Get()))
				return md;
		} else {
			if (lkey == StringToLower(md->GetInternalName()))
				return md;
		}

		if (lkey == StringToLower(md->GetFallbackName().Get()))
			return md;
	}

	return nullptr;
}


std::string DefTagMetaData::GetTypeName(const std::type_info& typeInfo)
{
	// demangle typename
#ifndef _MSC_VER
	int status;
	char* ctname = abi::__cxa_demangle(typeInfo.name(), 0, 0, &status);
	const std::string tname = ctname;
	free(ctname);
#else
	const std::string tname(typeInfo.name()); // FIXME?
#endif
	return tname;
}


/**
 * @brief Call Quote if type is not bool, float or int.
 */
static inline std::string Quote(const std::string& type, const std::string& value)
{
	if (type == "std::string")
		return Quote(value);

	return value;
}


/**
 * @brief Write a DefTagMetaData to a stream.
 */
static std::ostream& operator<< (std::ostream& out, const DefTagMetaData* d)
{
	const char* const OUTER_INDENT = "    ";
	const char* const INDENT = "      ";

	const std::string tname = DefTagMetaData::GetTypeName(d->GetTypeInfo());

	out << OUTER_INDENT << Quote(d->GetKey()) << ": {\n";

#define KV(key, value) out << INDENT << Quote(#key) << ": " << (value) << ",\n"

	if (d->GetDeclarationFile().IsSet())
		KV(declarationFile, Quote(d->GetDeclarationFile().Get()));

	if (d->GetDeclarationLine().IsSet())
		KV(declarationLine, d->GetDeclarationLine().Get());

	if (d->GetExternalName().IsSet())
		KV(internalName, Quote(d->GetInternalName()));

	if (d->GetFallbackName().IsSet())
		KV(fallbackName, Quote(d->GetFallbackName().Get()));

	if (d->GetDescription().IsSet())
		KV(description, Quote(d->GetDescription().Get()));

	if (d->GetDefaultValue().IsSet())
		KV(defaultValue, Quote(tname, d->GetDefaultValue().ToString()));

	if (d->GetMinimumValue().IsSet())
		KV(minimumValue, Quote(tname, d->GetMinimumValue().ToString()));

	if (d->GetMaximumValue().IsSet())
		KV(maximumValue, Quote(tname, d->GetMaximumValue().ToString()));

	if (d->GetScaleValue().IsSet())
		KV(scaleValue, Quote(tname, d->GetScaleValue().ToString()));

	if (d->GetScaleValueStr().IsSet())
		KV(scaleValueString, Quote(d->GetScaleValueStr().ToString()));

	if (d->GetTagFunctionStr().IsSet())
		KV(tagFunction, Quote(d->GetTagFunctionStr().ToString()));

	// Type is required.
	// Easiest to do this last because of the trailing comma that isn't there.
	out << INDENT << Quote("type") << ": " << Quote(tname) << "\n";

#undef KV

	out << OUTER_INDENT << "}";

	return out;
}

/**
 * @brief Output config variable meta data as JSON to stdout.
 *
 * This can be tested using, for example:
 *
 *	./spring --list-def-tags |
 *		python -c 'import json, sys; json.dump(json.load(sys.stdin), sys.stdout)'
 */
void DefType::OutputMetaDataMap() const
{
	cout << "{\n";

	bool first = true;

	for (unsigned int i = 0; i < tagMetaDataCnt; i++) {
		const DefTagMetaData* md = tagMetaData[i];

		if (!first)
			cout << ",\n";

		cout << md;
		first = false;
	}

	cout << "\n  }";
}

void DefType::OutputTagMap()
{
	cout << "{\n";

	bool first = true;
	for (const DefType* defType: GetTypes()) {
		if (!first)
			cout << ",\n";

		cout << "  " << Quote(defType->GetName()) << ": ";
		defType->OutputMetaDataMap();
		first = false;
	}

	cout << "\n}\n";
}


void DefType::CheckType(const DefTagMetaData* meta, const std::type_info& want)
{
	assert(meta != nullptr);
	if (meta->GetTypeInfo() != want)
		LOG_L(L_ERROR, "DEFTAG \"%s\" defined with wrong typevalue \"%s\" should be \"%s\"", meta->GetKey().c_str(), DefTagMetaData::GetTypeName(meta->GetTypeInfo()).c_str(), DefTagMetaData::GetTypeName(want).c_str());
	assert(meta->GetTypeInfo() == want);
}


void DefType::ReportUnknownTags(const std::string& instanceName, const LuaTable& luaTable, const std::string pre)
{
	std::vector<std::string> keys;
	luaTable.GetKeys(keys);

	for (const std::string& tag: keys) {
		const DefTagMetaData* meta = GetMetaDataByExternalKey(pre + tag);

		if (meta != nullptr)
			continue;

		if (luaTable.GetType(tag) == LuaTable::TABLE) {
			ReportUnknownTags(instanceName, luaTable.SubTable(tag), pre + tag + ".");
			continue;
		}

		LOG_L(L_WARNING, "%s: Unknown tag \"%s%s\" in \"%s\"", name, pre.c_str(), tag.c_str(), instanceName.c_str());
	}
}


void DefType::Load(void* instance, const LuaTable& luaTable)
{
	this->luaTable = &luaTable;

	for (unsigned int i = 0; i < defInitFuncCnt; i++) {
		defInitFuncs[i](instance);
	}

	this->luaTable = nullptr;
}