ConsoleRules.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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; // Should never happen!
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 }

Generated on Mon Feb 16 15:14:37 2009 for Scorched3D by  doxygen 1.5.3