00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <console/ConsoleRules.h>
00022 #include <console/Console.h>
00023 #include <common/Defines.h>
00024
00025 ConsoleRules::ConsoleRules()
00026 {
00027
00028 }
00029
00030 ConsoleRules::~ConsoleRules()
00031 {
00032
00033 }
00034
00035 void ConsoleRules::addRule(ConsoleRule *rule)
00036 {
00037 removeRule(rule);
00038
00039 std::string addName = rule->getName();
00040 _strlwr((char *) addName.c_str());
00041 rules_.insert(std::pair<std::string, ConsoleRule *>(addName, rule));
00042 }
00043
00044 void ConsoleRules::removeRule(ConsoleRule *rule)
00045 {
00046 std::multimap<std::string, ConsoleRule *>::iterator itor;
00047 for (itor = rules_.begin();
00048 itor != rules_.end();
00049 itor++)
00050 {
00051 ConsoleRule *r = itor->second;
00052 if (r == rule)
00053 {
00054 rules_.erase(itor);
00055 break;
00056 }
00057 }
00058 }
00059
00060 std::string ConsoleRules::matchRule(const char *line,
00061 std::vector<ConsoleRule *> &matches)
00062 {
00063 std::vector<ConsoleRuleValue> values;
00064 parseLine(line, values);
00065
00066 if (values.empty())
00067 {
00068 std::multimap<std::string, ConsoleRule *>::iterator itor;
00069 for (itor = rules_.begin();
00070 itor != rules_.end();
00071 itor++)
00072 {
00073 ConsoleRule *rule = itor->second;
00074 matches.push_back((*itor).second);
00075 }
00076 return "";
00077 }
00078 else
00079 {
00080 std::multimap<std::string, ConsoleRule *>::iterator itor;
00081 for (itor = rules_.begin();
00082 itor != rules_.end();
00083 itor++)
00084 {
00085 ConsoleRule *rule = itor->second;
00086 ConsoleRuleValue &nameValue = values[0];
00087
00088 if (values.size() == 1)
00089 {
00090 unsigned int nameLen = strlen(rule->getName());
00091 if (nameLen >= nameValue.valueString.length() &&
00092 _strnicmp(line, rule->getName(), nameValue.valueString.length()) == 0)
00093 {
00094 matches.push_back((*itor).second);
00095 }
00096 }
00097 else
00098 {
00099 if (0 == stricmp(rule->getName(), nameValue.valueString.c_str()))
00100 {
00101 if (rule->matchesPartialParams(values))
00102 {
00103 matches.push_back((*itor).second);
00104 }
00105 }
00106 }
00107 }
00108
00109 if (matches.empty()) return "";
00110 if (matches.size() == 1) return matches[0]->toString(values);
00111
00112 ConsoleRuleValue &firstValue = values[0];
00113 for (int i=(int) firstValue.valueString.length();; i++)
00114 {
00115 ConsoleRule *firstRule = matches[0];
00116 for (int j=0; j<(int)matches.size(); j++)
00117 {
00118 ConsoleRule *secondRule = matches[j];
00119 std::string firstString = firstRule->toString(values);
00120 std::string secondString = secondRule->toString(values);
00121
00122 if ((int) strlen(secondString.c_str()) < i ||
00123 0 != _strnicmp(secondString.c_str(), firstString.c_str(), i))
00124 {
00125 std::string buffer;
00126 buffer.append(secondString.c_str(), i - 1);
00127 return buffer;
00128 }
00129 }
00130 }
00131 }
00132
00133 return "";
00134 }
00135
00136 void ConsoleRules::addLine(Console *console, const char *line)
00137 {
00138 std::vector<ConsoleRuleValue> values;
00139 if (!parseLine(line, values))
00140 {
00141 console->addLine(false, S3D::formatStringBuffer(
00142 "Non terminated quote in : %s",
00143 line));
00144 return;
00145 }
00146
00147 if (values.empty()) return;
00148
00149 std::vector<ConsoleRule *> closeMatches;
00150 ConsoleRule *exactMatch = matchRule(values, closeMatches);
00151 if (exactMatch)
00152 {
00153 exactMatch->runRule(console, line, values);
00154 }
00155 else
00156 {
00157 std::string valuesString = ConsoleRule::valuesToString(values);
00158 console->addLine(false, "Unrecognised function :");
00159 console->addLine(false, S3D::formatStringBuffer(
00160 " %s",
00161 valuesString.c_str()));
00162 if (!closeMatches.empty())
00163 {
00164 console->addLine(false, "Possible matches are :");
00165 std::vector<ConsoleRule *>::iterator itor;
00166 for (itor = closeMatches.begin();
00167 itor != closeMatches.end();
00168 itor++)
00169 {
00170 std::string text = (*itor)->toString();
00171 console->addLine(false, S3D::formatStringBuffer(
00172 " %s", text.c_str()));
00173 }
00174 }
00175 }
00176 }
00177
00178 ConsoleRule *ConsoleRules::matchRule(
00179 std::vector<ConsoleRuleValue> &values,
00180 std::vector<ConsoleRule *> &closeMatches)
00181 {
00182 std::multimap<int, ConsoleRule *> matchedRules;
00183
00184 ConsoleRuleValue firstValue = values.front();
00185 _strlwr((char *)firstValue.valueString.c_str());
00186 std::pair<RulesMap::iterator, RulesMap::iterator> itp =
00187 rules_.equal_range(firstValue.valueString);
00188 for (RulesMap::iterator itor = itp.first; itor != itp.second; ++itor)
00189 {
00190 ConsoleRule *rule = itor->second;
00191 matchedRules.insert(
00192 std::pair<int, ConsoleRule *>(
00193 (int) rule->getParams().size(), rule));
00194 }
00195
00196 if (matchedRules.empty()) return 0;
00197
00198 std::vector<ConsoleRule *>::iterator ruleItor;
00199 std::vector<ConsoleRule *> sameNumberArgs;
00200 getMatchedRules(sameNumberArgs, matchedRules, (int) values.size() - 1);
00201 if (!sameNumberArgs.empty())
00202 {
00203 for (ruleItor = sameNumberArgs.begin();
00204 ruleItor != sameNumberArgs.end();
00205 ruleItor++)
00206 {
00207 ConsoleRule *rule = *ruleItor;
00208 closeMatches.push_back(rule);
00209 if (rule->matchesExactParams(values))
00210 {
00211 closeMatches.clear();
00212 return rule;
00213 }
00214 }
00215 }
00216
00217 return 0;
00218 }
00219
00220 void ConsoleRules::getMatchedRules(
00221 std::vector<ConsoleRule *> &result,
00222 std::multimap<int, ConsoleRule *> &matchedRules,
00223 int argCount)
00224 {
00225 result.clear();
00226 std::pair<
00227 std::multimap<int, ConsoleRule *>::iterator,
00228 std::multimap<int, ConsoleRule *>::iterator> itp =
00229 matchedRules.equal_range(argCount);
00230 for (std::multimap<int, ConsoleRule *>::iterator itor = itp.first;
00231 itor != itp.second;
00232 ++itor)
00233 {
00234 ConsoleRule *rule = itor->second;
00235 result.push_back(rule);
00236 }
00237 }
00238
00239 bool ConsoleRules::parseLine(const char *line,
00240 std::vector<ConsoleRuleValue> &split)
00241 {
00242 int pos = -1;
00243 bool inQuote = false;
00244 std::string currentEntry;
00245 for (int i=0; i<(int) strlen(line)+1; i++)
00246 {
00247 const char c = line[i];
00248
00249 if (c == '\0')
00250 {
00251 if (inQuote) return false;
00252 parseAddLine(pos, currentEntry.c_str(), split);
00253 currentEntry = ""; pos = -1;
00254
00255 return true;
00256 }
00257 else if (c == '=' &&
00258 ((split.size() == 1 && currentEntry.empty()) ||
00259 (split.size() == 0 && !currentEntry.empty())))
00260 {
00261 parseAddLine(pos, currentEntry.c_str(), split);
00262 currentEntry = ""; pos = -1;
00263 }
00264 else if ((c == ' ') && !inQuote)
00265 {
00266 parseAddLine(pos, currentEntry.c_str(), split);
00267 currentEntry = ""; pos = -1;
00268 }
00269 else if (c == '\"')
00270 {
00271 inQuote = !inQuote;
00272 }
00273 else
00274 {
00275 if (pos == -1) pos = i;
00276 currentEntry += c;
00277 }
00278 }
00279
00280 return !inQuote;
00281 }
00282
00283 void ConsoleRules::parseAddLine(int position, const char *line,
00284 std::vector<ConsoleRuleValue> &split)
00285 {
00286 int n = (int) strlen(line);
00287 if (n == 0) return;
00288
00289 ConsoleRuleValue newSplit;
00290 newSplit.valueString = line;
00291 newSplit.position = position;
00292
00293 if (strcmp(line, "on") == 0)
00294 {
00295 newSplit.type = ConsoleRuleTypeBoolean;
00296 newSplit.valueBool = true;
00297 }
00298 else if (strcmp(line, "off") == 0)
00299 {
00300 newSplit.type = ConsoleRuleTypeBoolean;
00301 newSplit.valueBool = false;
00302 }
00303 else
00304 {
00305 bool numbersOnly = true;
00306 for (int i=0; i<n; i++)
00307 {
00308 if ((line[i] < '0') || (line[i] > '9'))
00309 {
00310 if (line[i]!='.')
00311 {
00312 numbersOnly = false;
00313 break;
00314 }
00315 }
00316 }
00317
00318 if (numbersOnly)
00319 {
00320 newSplit.type = ConsoleRuleTypeNumber;
00321 newSplit.valueNumber = (float) atof(line);
00322 }
00323 else
00324 {
00325 newSplit.type = ConsoleRuleTypeString;
00326 }
00327 }
00328
00329 split.push_back(newSplit);
00330 }
00331
00332 void ConsoleRules::dump(std::vector<std::string> &resultList)
00333 {
00334 std::multimap<std::string, ConsoleRule *>::iterator itor;
00335 for (itor = rules_.begin();
00336 itor != rules_.end();
00337 itor++)
00338 {
00339 ConsoleRule *rule = itor->second;
00340 resultList.push_back(rule->toString());
00341 }
00342 }