Handle OptionEntryEnum in the console
[scorched3d/parasti.git] / src / client / console / ConsoleRules.cpp
blob1f5db578f84c4a8e6e7d160061646926daee7383
1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2009
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D 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.
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with Scorched3D; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ////////////////////////////////////////////////////////////////////////////////
21 #include <console/ConsoleRules.h>
22 #include <console/Console.h>
23 #include <common/Defines.h>
25 ConsoleRules::ConsoleRules()
30 ConsoleRules::~ConsoleRules()
35 void ConsoleRules::addRule(ConsoleRule *rule)
37 removeRule(rule);
39 std::string addName = rule->getName();
40 _strlwr((char *) addName.c_str());
41 rules_.insert(std::pair<std::string, ConsoleRule *>(addName, rule));
44 void ConsoleRules::removeRule(ConsoleRule *rule)
46 std::multimap<std::string, ConsoleRule *>::iterator itor;
47 for (itor = rules_.begin();
48 itor != rules_.end();
49 itor++)
51 ConsoleRule *r = itor->second;
52 if (r == rule)
54 rules_.erase(itor);
55 break;
60 std::string ConsoleRules::matchRule(const char *line,
61 std::vector<ConsoleRule *> &matches)
63 std::vector<ConsoleRuleValue> values;
64 parseLine(line, values);
66 if (values.empty())
68 std::multimap<std::string, ConsoleRule *>::iterator itor;
69 for (itor = rules_.begin();
70 itor != rules_.end();
71 itor++)
73 ConsoleRule *rule = itor->second;
74 matches.push_back((*itor).second);
76 return "";
78 else
80 std::multimap<std::string, ConsoleRule *>::iterator itor;
81 for (itor = rules_.begin();
82 itor != rules_.end();
83 itor++)
85 ConsoleRule *rule = itor->second;
86 ConsoleRuleValue &nameValue = values[0];
88 if (values.size() == 1)
90 unsigned int nameLen = strlen(rule->getName());
91 if (nameLen >= nameValue.valueString.length() &&
92 _strnicmp(line, rule->getName(), nameValue.valueString.length()) == 0)
94 matches.push_back((*itor).second);
97 else
99 if (0 == stricmp(rule->getName(), nameValue.valueString.c_str()))
101 if (rule->matchesPartialParams(values))
103 matches.push_back((*itor).second);
109 if (matches.empty()) return "";
110 if (matches.size() == 1) return matches[0]->toString(values);
112 ConsoleRuleValue &firstValue = values[0];
113 for (int i=(int) firstValue.valueString.length();; i++)
115 ConsoleRule *firstRule = matches[0];
116 for (int j=0; j<(int)matches.size(); j++)
118 ConsoleRule *secondRule = matches[j];
119 std::string firstString = firstRule->toString(values);
120 std::string secondString = secondRule->toString(values);
122 if ((int) strlen(secondString.c_str()) < i ||
123 0 != _strnicmp(secondString.c_str(), firstString.c_str(), i))
125 std::string buffer;
126 buffer.append(secondString.c_str(), i - 1);
127 return buffer;
133 return "";
136 void ConsoleRules::addLine(Console *console, const char *line)
138 std::vector<ConsoleRuleValue> values;
139 if (!parseLine(line, values))
141 console->addLine(false, S3D::formatStringBuffer(
142 "Non terminated quote in : %s",
143 line));
144 return;
147 if (values.empty()) return; // Should never happen!
149 std::vector<ConsoleRule *> closeMatches;
150 ConsoleRule *exactMatch = matchRule(values, closeMatches);
151 if (exactMatch)
153 exactMatch->runRule(console, line, values);
155 else
157 std::string valuesString = ConsoleRule::valuesToString(values);
158 console->addLine(false, "Unrecognised function :");
159 console->addLine(false, S3D::formatStringBuffer(
160 " %s",
161 valuesString.c_str()));
162 if (!closeMatches.empty())
164 console->addLine(false, "Possible matches are :");
165 std::vector<ConsoleRule *>::iterator itor;
166 for (itor = closeMatches.begin();
167 itor != closeMatches.end();
168 itor++)
170 std::string text = (*itor)->toString();
171 console->addLine(false, S3D::formatStringBuffer(
172 " %s", text.c_str()));
178 ConsoleRule *ConsoleRules::matchRule(
179 std::vector<ConsoleRuleValue> &values,
180 std::vector<ConsoleRule *> &closeMatches)
182 std::multimap<int, ConsoleRule *> matchedRules;
184 ConsoleRuleValue firstValue = values.front();
185 _strlwr((char *)firstValue.valueString.c_str());
186 std::pair<RulesMap::iterator, RulesMap::iterator> itp =
187 rules_.equal_range(firstValue.valueString);
188 for (RulesMap::iterator itor = itp.first; itor != itp.second; ++itor)
190 ConsoleRule *rule = itor->second;
191 matchedRules.insert(
192 std::pair<int, ConsoleRule *>(
193 (int) rule->getParams().size(), rule));
196 if (matchedRules.empty()) return 0;
198 std::vector<ConsoleRule *>::iterator ruleItor;
199 std::vector<ConsoleRule *> sameNumberArgs;
200 getMatchedRules(sameNumberArgs, matchedRules, (int) values.size() - 1);
201 if (!sameNumberArgs.empty())
203 for (ruleItor = sameNumberArgs.begin();
204 ruleItor != sameNumberArgs.end();
205 ruleItor++)
207 ConsoleRule *rule = *ruleItor;
208 closeMatches.push_back(rule);
209 if (rule->matchesExactParams(values))
211 closeMatches.clear();
212 return rule;
217 return 0;
220 void ConsoleRules::getMatchedRules(
221 std::vector<ConsoleRule *> &result,
222 std::multimap<int, ConsoleRule *> &matchedRules,
223 int argCount)
225 result.clear();
226 std::pair<
227 std::multimap<int, ConsoleRule *>::iterator,
228 std::multimap<int, ConsoleRule *>::iterator> itp =
229 matchedRules.equal_range(argCount);
230 for (std::multimap<int, ConsoleRule *>::iterator itor = itp.first;
231 itor != itp.second;
232 ++itor)
234 ConsoleRule *rule = itor->second;
235 result.push_back(rule);
239 bool ConsoleRules::parseLine(const char *line,
240 std::vector<ConsoleRuleValue> &split)
242 int pos = -1;
243 bool inQuote = false;
244 std::string currentEntry;
245 for (int i=0; i<(int) strlen(line)+1; i++)
247 const char c = line[i];
249 if (c == '\0')
251 if (inQuote) return false;
252 parseAddLine(pos, currentEntry.c_str(), split);
253 currentEntry = ""; pos = -1;
255 return true;
257 else if (c == '=' &&
258 ((split.size() == 1 && currentEntry.empty()) ||
259 (split.size() == 0 && !currentEntry.empty())))
261 parseAddLine(pos, currentEntry.c_str(), split);
262 currentEntry = ""; pos = -1;
264 else if ((c == ' ') && !inQuote)
266 parseAddLine(pos, currentEntry.c_str(), split);
267 currentEntry = ""; pos = -1;
269 else if (c == '\"')
271 inQuote = !inQuote;
273 else
275 if (pos == -1) pos = i;
276 currentEntry += c;
280 return !inQuote;
283 void ConsoleRules::parseAddLine(int position, const char *line,
284 std::vector<ConsoleRuleValue> &split)
286 int n = (int) strlen(line);
287 if (n == 0) return;
289 ConsoleRuleValue newSplit;
290 newSplit.valueString = line;
291 newSplit.position = position;
293 if (strcmp(line, "on") == 0)
295 newSplit.type = ConsoleRuleTypeBoolean;
296 newSplit.valueBool = true;
298 else if (strcmp(line, "off") == 0)
300 newSplit.type = ConsoleRuleTypeBoolean;
301 newSplit.valueBool = false;
303 else
305 bool numbersOnly = true;
306 for (int i=0; i<n; i++)
308 if ((line[i] < '0') || (line[i] > '9'))
310 if (line[i]!='.')
312 numbersOnly = false;
313 break;
318 if (numbersOnly)
320 newSplit.type = ConsoleRuleTypeNumber;
321 newSplit.valueNumber = (float) atof(line);
323 else
325 newSplit.type = ConsoleRuleTypeString;
329 split.push_back(newSplit);
332 void ConsoleRules::dump(std::vector<std::string> &resultList)
334 std::multimap<std::string, ConsoleRule *>::iterator itor;
335 for (itor = rules_.begin();
336 itor != rules_.end();
337 itor++)
339 ConsoleRule *rule = itor->second;
340 resultList.push_back(rule->toString());