1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include "ConfigVariable.h"
4 #include "System/Log/ILog.h"
5 #include <iostream>
6
7 using std::cout;
8 using std::map;
9 using std::string;
10
11 /**
12 * @brief Log an error about a ConfigVariableMetaData
13 */
14 #define LOG_VAR(data, fmt, ...) \
15 LOG_L(L_ERROR, "%s:%d: " fmt, data->GetDeclarationFile().Get().c_str(), data->GetDeclarationLine().Get(), ## __VA_ARGS__) \
16
17
GetMutableMetaDataMap()18 ConfigVariable::MetaDataMap& ConfigVariable::GetMutableMetaDataMap()
19 {
20 static MetaDataMap vars;
21 return vars;
22 }
23
GetMetaDataMap()24 const ConfigVariable::MetaDataMap& ConfigVariable::GetMetaDataMap()
25 {
26 return GetMutableMetaDataMap();
27 }
28
AddMetaData(const ConfigVariableMetaData * data)29 void ConfigVariable::AddMetaData(const ConfigVariableMetaData* data)
30 {
31 MetaDataMap& vars = GetMutableMetaDataMap();
32 MetaDataMap::const_iterator pos = vars.find(data->GetKey());
33
34 if (pos != vars.end()) {
35 LOG_VAR(data, "Duplicate config variable declaration \"%s\"", data->GetKey().c_str());
36 LOG_VAR(pos->second, " Previously declared here");
37 }
38 else {
39 vars[data->GetKey()] = data;
40 }
41 }
42
GetMetaData(const string & key)43 const ConfigVariableMetaData* ConfigVariable::GetMetaData(const string& key)
44 {
45 const MetaDataMap& vars = GetMetaDataMap();
46 MetaDataMap::const_iterator pos = vars.find(key);
47
48 if (pos != vars.end()) {
49 return pos->second;
50 }
51 else {
52 return NULL;
53 }
54 }
55
56 #ifdef DEBUG
57 CONFIG(std::string, test)
58 .defaultValue("x y z")
59 .description("\"quoted\", escaped: \\, \b, \f, \n, \r, \t");
60 #endif
61
62
63 /**
64 * @brief Call Quote if type is not bool, float or int.
65 */
Quote(const string & type,const string & value)66 static inline string Quote(const string& type, const string& value)
67 {
68 if (type == "bool" || type == "float" || type == "int") {
69 return value;
70 }
71 else {
72 return Quote(value);
73 }
74 }
75
76 /**
77 * @brief Write a ConfigVariableMetaData to a stream.
78 */
operator <<(std::ostream & out,const ConfigVariableMetaData * d)79 static std::ostream& operator<< (std::ostream& out, const ConfigVariableMetaData* d)
80 {
81 const char* const OUTER_INDENT = " ";
82 const char* const INDENT = " ";
83
84 out << OUTER_INDENT << Quote(d->GetKey()) << ": {\n";
85
86 #define KV(key, value) out << INDENT << Quote(#key) << ": " << (value) << ",\n"
87
88 if (d->GetDeclarationFile().IsSet()) {
89 KV(declarationFile, Quote(d->GetDeclarationFile().Get()));
90 }
91 if (d->GetDeclarationLine().IsSet()) {
92 KV(declarationLine, d->GetDeclarationLine().Get());
93 }
94 if (d->GetDescription().IsSet()) {
95 KV(description, Quote(d->GetDescription().Get()));
96 }
97 if (d->GetReadOnly().IsSet()) {
98 KV(readOnly, d->GetReadOnly().Get());
99 }
100 if (d->GetDefaultValue().IsSet()) {
101 KV(defaultValue, Quote(d->GetType(), d->GetDefaultValue().ToString()));
102 }
103 if (d->GetMinimumValue().IsSet()) {
104 KV(minimumValue, Quote(d->GetType(), d->GetMinimumValue().ToString()));
105 }
106 if (d->GetMaximumValue().IsSet()) {
107 KV(maximumValue, Quote(d->GetType(), d->GetMaximumValue().ToString()));
108 }
109 if (d->GetSafemodeValue().IsSet()) {
110 KV(safemodeValue, Quote(d->GetType(), d->GetSafemodeValue().ToString()));
111 }
112 // Type is required.
113 // Easiest to do this last because of the trailing comma that isn't there.
114 out << INDENT << Quote("type") << ": " << Quote(d->GetType()) << "\n";
115
116 #undef KV
117
118 out << OUTER_INDENT << "}";
119
120 return out;
121 }
122
123 /**
124 * @brief Output config variable meta data as JSON to stdout.
125 *
126 * This can be tested using, for example:
127 *
128 * ./spring --list-config-vars |
129 * python -c 'import json, sys; json.dump(json.load(sys.stdin), sys.stdout)'
130 */
OutputMetaDataMap()131 void ConfigVariable::OutputMetaDataMap()
132 {
133 cout << "{\n";
134
135 const MetaDataMap& mdm = GetMetaDataMap();
136 for (MetaDataMap::const_iterator it = mdm.begin(); it != mdm.end(); ++it) {
137 if (it != mdm.begin()) {
138 cout << ",\n";
139 }
140 cout << it->second;
141 }
142
143 cout << "\n}\n";
144 }
145