1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include "System/Info.h"
4
5 #include "System/Util.h"
6 #include "System/Exceptions.h"
7 #include "System/Log/ILog.h"
8 #include "Lua/LuaParser.h"
9
10 #include <assert.h>
11
12 static const char* InfoItem_badKeyChars = " =;\r\n\t";
13
info_getValueAsString(const InfoItem * infoItem)14 std::string info_getValueAsString(const InfoItem* infoItem) {
15
16 assert(infoItem != NULL);
17
18 std::string stringValue = "";
19
20 switch (infoItem->valueType) {
21 case INFO_VALUE_TYPE_STRING: {
22 stringValue = infoItem->valueTypeString;
23 } break;
24 case INFO_VALUE_TYPE_INTEGER: {
25 stringValue = IntToString(infoItem->value.typeInteger);
26 } break;
27 case INFO_VALUE_TYPE_FLOAT: {
28 stringValue = FloatToString(infoItem->value.typeFloat);
29 } break;
30 case INFO_VALUE_TYPE_BOOL: {
31 stringValue = IntToString((int) infoItem->value.typeBool);
32 } break;
33 }
34
35 return stringValue;
36 }
37
info_convertToStringValue(InfoItem * infoItem)38 void info_convertToStringValue(InfoItem* infoItem) {
39
40 assert(infoItem != NULL);
41
42 infoItem->valueTypeString = info_getValueAsString(infoItem);
43 infoItem->valueType = INFO_VALUE_TYPE_STRING;
44 }
45
info_convertTypeToString(InfoValueType infoValueType)46 const char* info_convertTypeToString(InfoValueType infoValueType) {
47
48 const char* typeString = NULL;
49
50 switch (infoValueType) {
51 case INFO_VALUE_TYPE_STRING: {
52 typeString = "string";
53 } break;
54 case INFO_VALUE_TYPE_INTEGER: {
55 typeString = "integer";
56 } break;
57 case INFO_VALUE_TYPE_FLOAT: {
58 typeString = "float";
59 } break;
60 case INFO_VALUE_TYPE_BOOL: {
61 typeString = "bool";
62 } break;
63 }
64
65 return typeString;
66 }
67
info_parseInfoItem(const LuaTable & root,int index,InfoItem & inf,std::set<string> & infoSet)68 static bool info_parseInfoItem(const LuaTable& root, int index, InfoItem& inf,
69 std::set<string>& infoSet)
70 {
71 const LuaTable& infsTbl = root.SubTable(index);
72 if (!infsTbl.IsValid()) {
73 LOG_L(L_WARNING, "parseInfoItem: subtable %d invalid", index);
74 return false;
75 }
76
77 // common info properties
78 inf.key = infsTbl.GetString("key", "");
79 if (inf.key.empty()
80 || (inf.key.find_first_of(InfoItem_badKeyChars) != string::npos)) {
81 LOG_L(L_WARNING,
82 "parseInfoItem: empty key or key contains bad characters");
83 return false;
84 }
85 std::string lowerKey = StringToLower(inf.key);
86 if (infoSet.find(inf.key) != infoSet.end()) {
87 LOG_L(L_WARNING, "parseInfoItem: key toLowerCase(%s) exists already",
88 inf.key.c_str());
89 return false;
90 }
91 // TODO add support for info value types other then string
92 inf.valueType = INFO_VALUE_TYPE_STRING;
93 inf.valueTypeString = infsTbl.GetString("value", "");
94 if (inf.valueTypeString.empty()) {
95 LOG_L(L_WARNING, "parseInfoItem: %s: empty value", inf.key.c_str());
96 return false;
97 }
98 inf.desc = infsTbl.GetString("desc", "");
99
100 infoSet.insert(lowerKey);
101
102 return true;
103 }
104
105
info_parseInfo(std::vector<InfoItem> & info,const std::string & fileName,const std::string & fileModes,const std::string & accessModes,std::set<std::string> * infoSet)106 void info_parseInfo(
107 std::vector<InfoItem>& info,
108 const std::string& fileName,
109 const std::string& fileModes,
110 const std::string& accessModes,
111 std::set<std::string>* infoSet)
112 {
113 LuaParser luaParser(fileName, fileModes, accessModes);
114
115 if (!luaParser.Execute()) {
116 throw content_error("luaParser.Execute() failed: "
117 + luaParser.GetErrorLog());
118 }
119
120 const LuaTable root = luaParser.GetRoot();
121 if (!root.IsValid()) {
122 throw content_error("root table invalid");
123 }
124
125 std::set<std::string>* myInfoSet = NULL;
126 if (infoSet == NULL) {
127 myInfoSet = new std::set<std::string>();
128 } else {
129 myInfoSet = infoSet;
130 }
131 for (int index = 1; root.KeyExists(index); index++) {
132 InfoItem inf;
133 if (info_parseInfoItem(root, index, inf, *myInfoSet)) {
134 info.push_back(inf);
135 }
136 }
137 if (infoSet == NULL) {
138 delete myInfoSet;
139 myInfoSet = NULL;
140 }
141 }
142
info_parseInfo(const std::string & fileName,const std::string & fileModes,const std::string & accessModes,std::set<std::string> * infoSet)143 std::vector<InfoItem> info_parseInfo(
144 const std::string& fileName,
145 const std::string& fileModes,
146 const std::string& accessModes,
147 std::set<std::string>* infoSet)
148 {
149 std::vector<InfoItem> info;
150
151 info_parseInfo(info, fileName, fileModes, accessModes, infoSet);
152
153 return info;
154 }
155