mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-11-18 05:11:42 +00:00
930 lines
24 KiB
C++
930 lines
24 KiB
C++
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "stdpch.h"
|
|
#include "interface_expr.h"
|
|
#include "interface_manager.h"
|
|
#include "interface_expr_node.h"
|
|
#include "../misc.h"
|
|
#include "nel/misc/algo.h"
|
|
#include <algorithm>
|
|
|
|
using namespace std;
|
|
using namespace NLMISC;
|
|
|
|
// Yoyo: Act like a singleton, else registerUserFct may crash.
|
|
CInterfaceExpr::TUserFctMap *CInterfaceExpr::_UserFct= NULL;
|
|
|
|
static const std::string ExprLuaId="lua:";
|
|
|
|
//==================================================================
|
|
// release memory
|
|
void CInterfaceExpr::release()
|
|
{
|
|
delete _UserFct;
|
|
_UserFct = NULL;
|
|
}
|
|
|
|
//==================================================================
|
|
void formatLuaCall(const std::string &expr, std::string &tempStr)
|
|
{
|
|
/* Call the LUA interface exp fct, with the script as line, and resolve string definition conflicts:
|
|
eg: replace
|
|
lua:getSkillFromName('SM')
|
|
into
|
|
lua('getSkillFromName(\"SM\")')
|
|
*/
|
|
tempStr= expr.substr(ExprLuaId.size()); // eg: tempStr= getSkillFromName('SM')
|
|
while(strFindReplace(tempStr, "'", "\\\"")); // eg: tempStr= getSkillFromName(\"SM\")
|
|
tempStr= string("lua('") + tempStr + "')"; // eg: tempStr= lua('getSkillFromName(\"SM\")')
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceExpr::eval(const std::string &expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes, bool noFctCalls /* = false */)
|
|
{
|
|
// Yoyo: Special InterfaceExpr Form to execute lua code?
|
|
if(expr.compare(0, ExprLuaId.size(), ExprLuaId) ==0 )
|
|
{
|
|
std::string tempStr;
|
|
formatLuaCall(expr, tempStr);
|
|
return evalExpr(tempStr.c_str(), result, nodes, noFctCalls) != NULL;
|
|
}
|
|
else
|
|
{
|
|
return evalExpr(expr.c_str(), result, nodes, noFctCalls) != NULL;
|
|
}
|
|
}
|
|
|
|
//==================================================================
|
|
CInterfaceExprNode *CInterfaceExpr::buildExprTree(const std::string &expr)
|
|
{
|
|
CInterfaceExprNode *node;
|
|
|
|
// Yoyo: Special InterfaceExpr Form to execute lua code?
|
|
if(expr.compare(0, ExprLuaId.size(), ExprLuaId) ==0 )
|
|
{
|
|
std::string tempStr;
|
|
formatLuaCall(expr, tempStr);
|
|
if (!buildExprTree(tempStr.c_str(), node)) return false;
|
|
}
|
|
else
|
|
{
|
|
if (!buildExprTree(expr.c_str(), node)) return false;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
|
|
//==================================================================
|
|
void CInterfaceExpr::registerUserFct(const char *name,TUserFct fct)
|
|
{
|
|
if(!_UserFct) _UserFct= new TUserFctMap;
|
|
|
|
nlassert(fct != NULL);
|
|
(*_UserFct)[std::string(name)] = fct;
|
|
}
|
|
|
|
//==================================================================
|
|
/** tool fct : skip space, tab and carret-returns
|
|
*/
|
|
static const char *skipBlank(const char *start)
|
|
{
|
|
nlassert(start);
|
|
while (*start == ' ' || *start == '\t' || *start == '\r' || *start == '\n') ++start;
|
|
return start;
|
|
}
|
|
|
|
//==================================================================
|
|
const char *CInterfaceExpr::evalExpr(const char *expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes, bool noFctCalls)
|
|
{
|
|
nlassert(expr != NULL);
|
|
expr = skipBlank(expr);
|
|
if (isalpha(*expr)) // alpha character means this is a function name
|
|
{
|
|
return evalFct(expr, result, nodes, noFctCalls);
|
|
}
|
|
else if (*expr == '@') // is it a database entry ?
|
|
{
|
|
++ expr;
|
|
expr = skipBlank(expr);
|
|
return evalDBEntry(expr, result, nodes);
|
|
}
|
|
|
|
// try to parse a literal value
|
|
const char *newExpr = result.initFromString(expr);
|
|
if (!newExpr)
|
|
{
|
|
nlwarning("<CInterfaceExpr::evalExpr> : syntax error : %s", expr);
|
|
return NULL;
|
|
}
|
|
return newExpr;
|
|
}
|
|
|
|
//==================================================================
|
|
const char *CInterfaceExpr::buildExprTree(const char *expr, CInterfaceExprNode *&result)
|
|
{
|
|
nlassert(expr != NULL);
|
|
expr = skipBlank(expr);
|
|
if (isalpha(*expr)) // alpha character means this is a function name
|
|
{
|
|
return buildFctNode(expr, result);
|
|
}
|
|
else if (*expr == '@') // is it a database entry ?
|
|
{
|
|
++ expr;
|
|
expr = skipBlank(expr);
|
|
return buildDBEntryNode(expr, result);
|
|
}
|
|
else
|
|
{
|
|
CInterfaceExprValue value;
|
|
// try to parse a literal value
|
|
const char *newExpr = value.initFromString(expr);
|
|
if (!newExpr)
|
|
{
|
|
nlwarning("<CInterfaceExpr::buildExprTree> : syntax error : %s", expr);
|
|
return NULL;
|
|
}
|
|
CInterfaceExprNodeValue *node = new CInterfaceExprNodeValue;
|
|
node->Value = value;
|
|
result = node;
|
|
return newExpr;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//==================================================================
|
|
const char *CInterfaceExpr::evalFct(const char *expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes, bool noFctCalls)
|
|
{
|
|
if(!_UserFct) _UserFct= new TUserFctMap;
|
|
|
|
const char *start = expr;
|
|
while (isalnum(*expr)) ++ expr;
|
|
std::string fctName(start, expr - start);
|
|
// find entry in the map
|
|
TUserFctMap::iterator fctIt = _UserFct->find(fctName);
|
|
if (fctIt == _UserFct->end())
|
|
{
|
|
nlwarning("<CInterfaceExpr::evalFct> : Unknown function %s", fctName.c_str());
|
|
return NULL;
|
|
}
|
|
nlassert(fctIt->second != NULL);
|
|
// eval list of arguments
|
|
TArgList argList;
|
|
expr = skipBlank(expr);
|
|
if (*expr != '(')
|
|
{
|
|
nlwarning("<CInterfaceExpr::evalFct> : '(' expected for function %s", fctName.c_str());
|
|
return NULL;
|
|
}
|
|
++ expr;
|
|
expr = skipBlank(expr);
|
|
if (*expr != ')')
|
|
{
|
|
for(;;)
|
|
{
|
|
expr = skipBlank(expr);
|
|
// parse an argument
|
|
argList.push_back(CInterfaceExprValue());
|
|
expr = evalExpr(expr, argList.back(), nodes, noFctCalls);
|
|
if (expr == NULL) return NULL;
|
|
expr = skipBlank(expr);
|
|
if (*expr == ')') break;
|
|
// if it isn't the end of the expression, then we should find a ',' before next argument
|
|
if (*expr != ',')
|
|
{
|
|
nlwarning("<CInterfaceExpr::evalFct> : ',' expected in function %s", fctName.c_str());
|
|
return NULL;
|
|
}
|
|
++ expr;
|
|
}
|
|
}
|
|
++ expr;
|
|
// call the fct
|
|
if (!noFctCalls) // should we make terminal function calls ?
|
|
{
|
|
if (fctIt->second(argList, result)) return expr;
|
|
}
|
|
else
|
|
{
|
|
return expr;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//==================================================================
|
|
const char *CInterfaceExpr::buildFctNode(const char *expr, CInterfaceExprNode *&result)
|
|
{
|
|
if(!_UserFct) _UserFct= new TUserFctMap;
|
|
|
|
const char *start = expr;
|
|
while (isalnum(*expr)) ++ expr;
|
|
std::string fctName(start, expr - start);
|
|
// find entry in the map
|
|
TUserFctMap::iterator fctIt = _UserFct->find(fctName);
|
|
if (fctIt == _UserFct->end())
|
|
{
|
|
nlwarning("<CInterfaceExpr::buildFctNode> : Unknown function %s", fctName.c_str());
|
|
return NULL;
|
|
}
|
|
nlassert(fctIt->second != NULL);
|
|
// List of parameters
|
|
expr = skipBlank(expr);
|
|
if (*expr != '(')
|
|
{
|
|
nlwarning("<CInterfaceExpr::buildFctNode> : '(' expected for function %s", fctName.c_str());
|
|
return NULL;
|
|
}
|
|
++ expr;
|
|
expr = skipBlank(expr);
|
|
std::vector<CInterfaceExprNode *> Params;
|
|
if (*expr != ')')
|
|
{
|
|
for(;;)
|
|
{
|
|
expr = skipBlank(expr);
|
|
// parse an argument
|
|
CInterfaceExprNode *node = NULL;
|
|
expr = buildExprTree(expr, node);
|
|
if (expr == NULL)
|
|
{
|
|
for(uint k = 0; k < Params.size(); ++k)
|
|
{
|
|
delete Params[k];
|
|
}
|
|
return NULL;
|
|
}
|
|
Params.push_back(node);
|
|
expr = skipBlank(expr);
|
|
if (*expr == ')') break;
|
|
// if it isn't the end of the expression, then we should find a ',' before next argument
|
|
if (*expr != ',')
|
|
{
|
|
for(uint k = 0; k < Params.size(); ++k)
|
|
{
|
|
delete Params[k];
|
|
}
|
|
nlwarning("CInterfaceExpr::evalFct : ',' expected in function %s", fctName.c_str());
|
|
return NULL;
|
|
}
|
|
++ expr;
|
|
}
|
|
}
|
|
++ expr;
|
|
CInterfaceExprNodeValueFnCall *node = new CInterfaceExprNodeValueFnCall;
|
|
node->Params.swap(Params);
|
|
node->Func = fctIt->second;
|
|
result = node;
|
|
return expr;
|
|
}
|
|
|
|
//==================================================================
|
|
const char *CInterfaceExpr::evalDBEntry(const char *expr, CInterfaceExprValue &result, std::vector<ICDBNode *> *nodes)
|
|
{
|
|
std::string dbEntry;
|
|
expr = unpackDBentry(expr, nodes, dbEntry);
|
|
if (!expr) return NULL;
|
|
// TestYoyo
|
|
//nlassert(CInterfaceManager::getInstance()->getDbProp(dbEntry, false) || CInterfaceManager::getInstance()->getDbBranch(dbEntry));
|
|
// get the db value
|
|
CCDBNodeLeaf *nl = CInterfaceManager::getInstance()->getDbProp(dbEntry);
|
|
if (nl)
|
|
{
|
|
if (nodes)
|
|
{
|
|
// insert node if not already present
|
|
if (std::find(nodes->begin(), nodes->end(), nl) == nodes->end())
|
|
{
|
|
nodes->push_back(nl);
|
|
}
|
|
}
|
|
result.setInteger(nl->getValue64());
|
|
return expr;
|
|
}
|
|
else
|
|
{
|
|
CCDBNodeBranch *nb = CInterfaceManager::getInstance()->getDbBranch(dbEntry);
|
|
if (nodes && nb)
|
|
{
|
|
if (std::find(nodes->begin(), nodes->end(), nb) == nodes->end())
|
|
{
|
|
nodes->push_back(nb);
|
|
}
|
|
}
|
|
if (!nb) return NULL;
|
|
result.setInteger(0);
|
|
return expr;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//==================================================================
|
|
const char *CInterfaceExpr::buildDBEntryNode(const char *expr, CInterfaceExprNode *&result)
|
|
{
|
|
std::string dbEntry;
|
|
bool indirection;
|
|
const char *startChar = expr;
|
|
expr = unpackDBentry(expr, NULL, dbEntry, &indirection);
|
|
if (!expr) return NULL;
|
|
if (indirection)
|
|
{
|
|
// special node with no optimisation
|
|
CInterfaceExprNodeDependantDBRead *node = new CInterfaceExprNodeDependantDBRead;
|
|
node->Expr.resize(expr - startChar + 1);
|
|
std::copy(startChar, expr, node->Expr.begin() + 1);
|
|
node->Expr[0] = '@';
|
|
result = node;
|
|
return expr;
|
|
}
|
|
else
|
|
{
|
|
// TestYoyo
|
|
//nlassert(CInterfaceManager::getInstance()->getDbProp(dbEntry, false) || CInterfaceManager::getInstance()->getDbBranch(dbEntry));
|
|
CCDBNodeLeaf *nl = CInterfaceManager::getInstance()->getDbProp(dbEntry);
|
|
if (nl)
|
|
{
|
|
CInterfaceExprNodeDBLeaf *node = new CInterfaceExprNodeDBLeaf;
|
|
node->Leaf = nl;
|
|
result = node;
|
|
return expr;
|
|
}
|
|
else
|
|
{
|
|
CCDBNodeBranch *nb = CInterfaceManager::getInstance()->getDbBranch(dbEntry);
|
|
if (nb)
|
|
{
|
|
CInterfaceExprNodeDBBranch *node = new CInterfaceExprNodeDBBranch;
|
|
node->Branch = nb;
|
|
result = node;
|
|
return expr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//==================================================================
|
|
const char *CInterfaceExpr::unpackDBentry(const char *expr, std::vector<ICDBNode *> *nodes, std::string &dest, bool *hasIndirections /* = NULL*/)
|
|
{
|
|
std::string entryName;
|
|
bool indirection = false;
|
|
for (;;)
|
|
{
|
|
if (*expr == '[')
|
|
{
|
|
indirection = true;
|
|
++ expr;
|
|
std::string subEntry;
|
|
expr = unpackDBentry(expr, nodes, subEntry);
|
|
if (!expr) return NULL;
|
|
// Read DB Index Offset.
|
|
sint32 indirectionOffset= 0;
|
|
if (*expr == '-' || *expr =='+' )
|
|
{
|
|
bool negative= *expr == '-';
|
|
std::string offsetString;
|
|
++ expr;
|
|
while(*expr!=0 && isdigit(*expr))
|
|
{
|
|
offsetString.push_back(*expr);
|
|
++ expr;
|
|
}
|
|
// get offset
|
|
fromString(offsetString, indirectionOffset);
|
|
if(negative)
|
|
indirectionOffset= -indirectionOffset;
|
|
}
|
|
// Test end of indirection
|
|
if (*expr != ']')
|
|
{
|
|
nlwarning("CInterfaceExpr::unpackDBentry: ']' expected");
|
|
return NULL;
|
|
}
|
|
++ expr;
|
|
// get the db value at sub entry
|
|
// TestYoyo
|
|
//nlassert(CInterfaceManager::getInstance()->getDbProp(subEntry, false) || CInterfaceManager::getInstance()->getDbBranch(subEntry));
|
|
CCDBNodeLeaf *nl = CInterfaceManager::getInstance()->getDbProp(subEntry);
|
|
if (nodes)
|
|
{
|
|
if (std::find(nodes->begin(), nodes->end(), nl) == nodes->end())
|
|
{
|
|
nodes->push_back(nl);
|
|
}
|
|
}
|
|
// compute indirection, (clamp).
|
|
sint32 indirectionValue= nl->getValue32() + indirectionOffset;
|
|
indirectionValue= std::max((sint32)0, indirectionValue);
|
|
|
|
// Append to entry name.
|
|
entryName += NLMISC::toString(indirectionValue);
|
|
}
|
|
else if (isalnum(*expr) || *expr == '_' || *expr == ':')
|
|
{
|
|
entryName += *expr;
|
|
++ expr;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (hasIndirections)
|
|
{
|
|
*hasIndirections = indirection;
|
|
}
|
|
dest = entryName;
|
|
return expr;
|
|
}
|
|
|
|
|
|
//==================================================================
|
|
bool CInterfaceExpr::evalAsInt(const std::string &expr, sint64 &dest)
|
|
{
|
|
CInterfaceExprValue result;
|
|
if (!eval(expr, result)) return false;
|
|
if (!result.toInteger())
|
|
{
|
|
nlwarning("<CInterfaceExpr::evalAsInt> Can't convert value to an integer, expr = %s", expr.c_str());
|
|
return false;
|
|
}
|
|
dest = result.getInteger();
|
|
return true;
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceExpr::evalAsDouble(const std::string &expr, double &dest)
|
|
{
|
|
CInterfaceExprValue result;
|
|
if (!eval(expr, result)) return false;
|
|
if (!result.toDouble())
|
|
{
|
|
nlwarning("<CInterfaceExpr::evalAsDouble> Can't convert value to a double, expr = %s", expr.c_str());
|
|
return false;
|
|
}
|
|
dest = result.getDouble();
|
|
return true;
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceExpr::evalAsBool(const std::string &expr, bool &dest)
|
|
{
|
|
CInterfaceExprValue result;
|
|
if (!eval(expr, result)) return false;
|
|
if (!result.toBool())
|
|
{
|
|
nlwarning("<CInterfaceExpr::evalAsBool> Can't convert value to a boolean, expr = %s", expr.c_str());
|
|
return false;
|
|
}
|
|
dest = result.getBool();
|
|
return true;
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceExpr::evalAsString(const std::string &expr, std::string &dest)
|
|
{
|
|
CInterfaceExprValue result;
|
|
if (!eval(expr, result)) return false;
|
|
if (!result.toString())
|
|
{
|
|
nlwarning("<CInterfaceExpr::evalAsString> Can't convert value to a string, expr = %s", expr.c_str());
|
|
return false;
|
|
}
|
|
dest = result.getString();
|
|
return true;
|
|
}
|
|
|
|
//==================================================================
|
|
//==================================================================
|
|
//==================================================================
|
|
//==================================================================
|
|
|
|
|
|
//==================================================================
|
|
bool CInterfaceExprValue::toBool()
|
|
{
|
|
switch(_Type)
|
|
{
|
|
case Boolean: return true;
|
|
case Integer: setBool(_IntegerValue != 0); return true;
|
|
case Double: setBool(_DoubleValue != 0); return true;
|
|
case String: return evalBoolean(_StringValue.toString().c_str()) != NULL;
|
|
default: break;
|
|
}
|
|
return false;
|
|
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceExprValue::toInteger()
|
|
{
|
|
switch(_Type)
|
|
{
|
|
case Boolean: setInteger(_BoolValue ? 1 : 0); return true;
|
|
case Integer: return true;
|
|
case Double: setInteger((sint64) _DoubleValue); return true;
|
|
case String:
|
|
if (evalNumber(_StringValue.toString().c_str())) return toInteger();
|
|
return false;
|
|
case RGBA: setInteger((sint64) _RGBAValue); return true;
|
|
default: break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceExprValue::toDouble()
|
|
{
|
|
switch(_Type)
|
|
{
|
|
case Boolean: setDouble(_BoolValue ? 1 : 0); return true;
|
|
case Integer: setDouble((double) _IntegerValue); return true;
|
|
case Double: return true;
|
|
case String:
|
|
if (evalNumber(_StringValue.toString().c_str())) return toBool();
|
|
return false;
|
|
case RGBA: setDouble((double) _RGBAValue); return true;
|
|
default: break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceExprValue::toString()
|
|
{
|
|
switch(_Type)
|
|
{
|
|
case Boolean: setString(_BoolValue ? "true" : "false"); return true;
|
|
case Integer: setString(NLMISC::toString(_IntegerValue)); return true;
|
|
case Double: setString(NLMISC::toString("%.2f", _DoubleValue)); return true;
|
|
case String: return true;
|
|
case RGBA:
|
|
{
|
|
uint r,g,b,a;
|
|
r= (_RGBAValue&0xff);
|
|
g= ((_RGBAValue>>8)&0xff);
|
|
b= ((_RGBAValue>>16)&0xff);
|
|
a= ((_RGBAValue>>24)&0xff);
|
|
setString(NLMISC::toString("%d %d %d %d", r, g, b, a));
|
|
return true;
|
|
}
|
|
default: break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceExprValue::toRGBA()
|
|
{
|
|
switch(_Type)
|
|
{
|
|
case RGBA: return true;
|
|
case Integer: setRGBA(NLMISC::CRGBA((uint8)(_IntegerValue&0xff), (uint8)((_IntegerValue>>8)&0xff),
|
|
(uint8)((_IntegerValue>>16)&0xff), (uint8)((_IntegerValue>>24)&0xff))); return true;
|
|
case String:
|
|
setRGBA(stringToRGBA(_StringValue.toString().c_str())); return true;
|
|
default: break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceExprValue::isNumerical() const
|
|
{
|
|
return _Type == Boolean || _Type == Integer || _Type == Double;
|
|
}
|
|
|
|
//==================================================================
|
|
const char *CInterfaceExprValue::initFromString(const char *expr)
|
|
{
|
|
nlassert(expr);
|
|
expr = skipBlank(expr);
|
|
if (isdigit(*expr) || *expr == '.' || *expr == '-') return evalNumber(expr);
|
|
switch(*expr)
|
|
{
|
|
case 't':
|
|
case 'T':
|
|
case 'f':
|
|
case 'F':
|
|
return evalBoolean(expr);
|
|
case '\'':
|
|
return evalString(expr);
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//==================================================================
|
|
const char *CInterfaceExprValue::evalBoolean(const char *expr)
|
|
{
|
|
nlassert(expr);
|
|
expr = skipBlank(expr);
|
|
if (toupper(expr[0]) == 'T' &&
|
|
toupper(expr[1]) == 'R' &&
|
|
toupper(expr[2]) == 'U' &&
|
|
toupper(expr[3]) == 'E')
|
|
{
|
|
setBool(true);
|
|
return expr + 4;
|
|
}
|
|
//
|
|
if (toupper(expr[0]) == 'F' &&
|
|
toupper(expr[1]) == 'A' &&
|
|
toupper(expr[2]) == 'L' &&
|
|
toupper(expr[3]) == 'S' &&
|
|
toupper(expr[4]) == 'E')
|
|
{
|
|
setBool(false);
|
|
return expr + 5;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//==================================================================
|
|
const char *CInterfaceExprValue::evalNumber(const char *expr)
|
|
{
|
|
bool negative;
|
|
bool hasPoint = false;
|
|
|
|
expr = skipBlank(expr);
|
|
|
|
if (*expr == '-')
|
|
{
|
|
negative = true;
|
|
++ expr;
|
|
expr = skipBlank(expr);
|
|
}
|
|
else
|
|
{
|
|
negative = false;
|
|
}
|
|
|
|
const char *start = expr;
|
|
while (*expr == '.' || isdigit(*expr))
|
|
{
|
|
if (*expr == '.') hasPoint = true;
|
|
++ expr;
|
|
}
|
|
if (start == expr) return NULL;
|
|
if (!hasPoint)
|
|
{
|
|
sint64 value = 0;
|
|
// this is an integer
|
|
for (const char *nbPtr = start; nbPtr < expr; ++ nbPtr)
|
|
{
|
|
value *= 10;
|
|
value += (sint64) (*nbPtr - '0');
|
|
}
|
|
setInteger(negative ? - value : value);
|
|
return expr;
|
|
}
|
|
else // floating point value : use scanf
|
|
{
|
|
// well, for now, we only parse a float
|
|
float value;
|
|
std::string floatValue(start, expr - start);
|
|
if (fromString(floatValue, value))
|
|
{
|
|
setDouble(negative ? - value : value);
|
|
return expr;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//==================================================================
|
|
const char *CInterfaceExprValue::evalString(const char *expr)
|
|
{
|
|
expr = skipBlank(expr);
|
|
if (*expr != '\'') return NULL;
|
|
++expr;
|
|
std::string str;
|
|
for (;;)
|
|
{
|
|
if (expr == '\0')
|
|
{
|
|
nlwarning("CInterfaceExprValue::evalString : end of buffer encountered in a string");
|
|
return NULL;
|
|
}
|
|
else
|
|
if (*expr == '\'')
|
|
{
|
|
++ expr;
|
|
break;
|
|
}
|
|
if (*expr == '\\') // special char
|
|
{
|
|
++ expr;
|
|
switch (*expr)
|
|
{
|
|
case 't': str += '\t'; break;
|
|
case 'r': str += '\r'; break;
|
|
case 'n': str += '\n'; break;
|
|
case '\'': str += '\''; break;
|
|
case '"': str += '"'; break;
|
|
case '\\': str += '\\'; break;
|
|
case '\n':
|
|
case '\r':
|
|
// string continue on next line, so do nothing
|
|
break;
|
|
case '\0': continue;
|
|
default:
|
|
nlwarning("CInterfaceExprValue::evalString : unknown escape sequence : \\%c", *expr);
|
|
if (*expr) str += *expr;
|
|
break;
|
|
}
|
|
}
|
|
else if (*expr == '\n' || *expr == '\r')
|
|
{
|
|
nlwarning("CInterfaceExprValue::evalString : line break encountered in a string");
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
str += *expr;
|
|
}
|
|
++ expr;
|
|
}
|
|
setString(str);
|
|
return expr;
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceExprValue::toType(TType type)
|
|
{
|
|
switch(type)
|
|
{
|
|
case Boolean: return toBool();
|
|
case Integer: return toInteger();
|
|
case Double: return toDouble();
|
|
case String: return toString();
|
|
case RGBA: return toRGBA();
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
|
|
//==================================================================
|
|
void CInterfaceExprValue::clean()
|
|
{
|
|
switch (_Type)
|
|
{
|
|
case String: _StringValue.clear(); break;
|
|
case UserType: delete _UserTypeValue; break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
//==================================================================
|
|
void CInterfaceExprValue::setUserType(CInterfaceExprUserType *value)
|
|
{
|
|
if (_Type == UserType && value == _UserTypeValue) return;
|
|
clean();
|
|
_Type = UserType;
|
|
_UserTypeValue = value;
|
|
}
|
|
|
|
//==================================================================
|
|
bool CInterfaceExprValue::getBool() const
|
|
{
|
|
if (_Type != Boolean)
|
|
{
|
|
nlwarning("<CInterfaceExprValue::getBool> bad type!");
|
|
return false;
|
|
}
|
|
return _BoolValue;
|
|
}
|
|
|
|
//==================================================================
|
|
sint64 CInterfaceExprValue::getInteger() const
|
|
{
|
|
if (_Type != Integer)
|
|
{
|
|
nlwarning("<CInterfaceExprValue::getInteger> bad type!");
|
|
return 0;
|
|
}
|
|
return _IntegerValue;
|
|
}
|
|
|
|
//==================================================================
|
|
double CInterfaceExprValue::getDouble() const
|
|
{
|
|
if (_Type != Double)
|
|
{
|
|
nlwarning("<CInterfaceExprValue::getDouble> bad type!");
|
|
return 0;
|
|
}
|
|
return _DoubleValue;
|
|
}
|
|
|
|
//==================================================================
|
|
std::string CInterfaceExprValue::getString() const
|
|
{
|
|
if (_Type != String)
|
|
{
|
|
nlwarning("<CInterfaceExprValue::getString> bad type!");
|
|
return "";
|
|
}
|
|
return _StringValue.toString();
|
|
}
|
|
|
|
//==================================================================
|
|
NLMISC::CRGBA CInterfaceExprValue::getRGBA() const
|
|
{
|
|
if (_Type != RGBA)
|
|
{
|
|
nlwarning("<CInterfaceExprValue::getRGBA> bad type!");
|
|
return CRGBA::White;
|
|
}
|
|
NLMISC::CRGBA col;
|
|
col.R = (uint8)(_RGBAValue&0xff);
|
|
col.G = (uint8)((_RGBAValue>>8)&0xff);
|
|
col.B = (uint8)((_RGBAValue>>16)&0xff);
|
|
col.A = (uint8)((_RGBAValue>>24)&0xff);
|
|
return col;
|
|
}
|
|
|
|
|
|
//==================================================================
|
|
const ucstring &CInterfaceExprValue::getUCString() const
|
|
{
|
|
if (_Type != String)
|
|
{
|
|
nlwarning("<CInterfaceExprValue::getString> bad type!");
|
|
static ucstring emptyString;
|
|
return emptyString;
|
|
}
|
|
return _StringValue;
|
|
}
|
|
|
|
//==================================================================
|
|
CInterfaceExprUserType *CInterfaceExprValue::getUserType() const
|
|
{
|
|
if (_Type != UserType)
|
|
{
|
|
nlwarning("<CInterfaceExprValue::getUserType> bad type!");
|
|
return NULL;
|
|
}
|
|
return _UserTypeValue;
|
|
}
|
|
|
|
//==================================================================
|
|
CInterfaceExprValue::CInterfaceExprValue(const CInterfaceExprValue &other) : _Type(NoType)
|
|
{
|
|
*this = other;
|
|
}
|
|
|
|
//==================================================================
|
|
CInterfaceExprValue &CInterfaceExprValue::operator = (const CInterfaceExprValue &other)
|
|
{
|
|
if (this != &other)
|
|
{
|
|
clean();
|
|
switch(other._Type)
|
|
{
|
|
case Boolean: _BoolValue = other._BoolValue; break;
|
|
case Integer: _IntegerValue = other._IntegerValue; break;
|
|
case Double: _DoubleValue = other._DoubleValue; break;
|
|
case String: _StringValue = other._StringValue; break;
|
|
case RGBA: _RGBAValue = other._RGBAValue; break;
|
|
case UserType:
|
|
if (other._UserTypeValue != NULL)
|
|
{
|
|
_UserTypeValue = other._UserTypeValue->clone();
|
|
}
|
|
else
|
|
{
|
|
_UserTypeValue = NULL;
|
|
}
|
|
break;
|
|
case NoType: break;
|
|
default:
|
|
nlwarning("<CInterfaceExprValue::operator=> bad source type") ;
|
|
return *this;
|
|
break;
|
|
}
|
|
_Type = other._Type;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
|