mirror of
https://projects.vdr-developer.org/git/vdr-plugin-skindesigner.git
synced 2023-10-19 17:58:31 +02:00
1606 lines
56 KiB
C
1606 lines
56 KiB
C
|
#include "complextypes.h"
|
||
|
#include "../config.h"
|
||
|
|
||
|
/******************************************************************
|
||
|
* helpers
|
||
|
******************************************************************/
|
||
|
char *RemoveSpace(char *e) {
|
||
|
if (!e)
|
||
|
return e;
|
||
|
int numSpaces = 0;
|
||
|
int exprLen = strlen(e);
|
||
|
for (int i = 0; i < exprLen; ++i) {
|
||
|
if (isspace(e[i]))
|
||
|
++numSpaces;
|
||
|
}
|
||
|
if (numSpaces == 0)
|
||
|
return e;
|
||
|
|
||
|
char *replaced = (char*)malloc(exprLen - numSpaces + 1);
|
||
|
replaced[exprLen - numSpaces] = '\0';
|
||
|
int j = 0;
|
||
|
for (int i = 0; i < exprLen; ++i) {
|
||
|
if (!isspace(e[i])){
|
||
|
replaced[j++] = e[i];
|
||
|
}
|
||
|
}
|
||
|
free(e);
|
||
|
return replaced;
|
||
|
}
|
||
|
|
||
|
void ReplaceDecimalpoint(char *e) {
|
||
|
int size = (int)strlen(e);
|
||
|
for ( int i = 0; i < size; ++i ) {
|
||
|
if (e[i] == '.')
|
||
|
e[i] = config.decPoint;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ReplaceStart(char *e, int num) {
|
||
|
int size = (int)strlen(e);
|
||
|
if (size <= num)
|
||
|
return;
|
||
|
for ( int i = 0; i < size; ++i ) {
|
||
|
if (i < size - num)
|
||
|
e[i] = e[i+num];
|
||
|
else e[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ReplaceEnd(char *e, int num) {
|
||
|
int size = (int)strlen(e) - 1;
|
||
|
if (size <= num)
|
||
|
return;
|
||
|
for ( int i = size; i > size-num; --i ) {
|
||
|
e[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
/******************************************************************
|
||
|
* cCond
|
||
|
******************************************************************/
|
||
|
cCond::cCond(const char *expression) {
|
||
|
this->expr = strdup(expression);
|
||
|
operation = eCondOp::tAnd;
|
||
|
type = eCondType::token;
|
||
|
constant = false;
|
||
|
isTrue = false;
|
||
|
tokenIndex = -1;
|
||
|
compareValue = -1;
|
||
|
compareStrValue = NULL;
|
||
|
}
|
||
|
|
||
|
cCond::cCond(const cCond &other) {
|
||
|
expr = strdup(other.expr);
|
||
|
operation = other.operation;
|
||
|
type = other.type;
|
||
|
constant = other.constant;
|
||
|
tokenType = other.tokenType;
|
||
|
isTrue = other.isTrue;
|
||
|
tokenIndex = other.tokenIndex;
|
||
|
compareValue = other.compareValue;
|
||
|
compareStrValue = NULL;
|
||
|
if (other.compareStrValue)
|
||
|
compareStrValue = strdup(other.compareStrValue);
|
||
|
}
|
||
|
|
||
|
cCond::~cCond(void) {
|
||
|
free(expr);
|
||
|
free(compareStrValue);
|
||
|
}
|
||
|
|
||
|
void cCond::Debug(void) {
|
||
|
esyslog("skindesigner: cond %s, operation %s, type %d", expr,
|
||
|
(operation == eCondOp::tAnd) ? "++" : "||",
|
||
|
(int)type);
|
||
|
if (constant)
|
||
|
esyslog("skindesigner: constant cond: %s", isTrue ? "TRUE" : "FALSE");
|
||
|
if (tokenIndex >= 0)
|
||
|
esyslog("skindesigner: token index: %d", tokenIndex);
|
||
|
if (compareValue >= 0)
|
||
|
esyslog("skindesigner: compare value: %d", compareValue);
|
||
|
if (compareStrValue)
|
||
|
esyslog("skindesigner: compare string value: %d", compareStrValue);
|
||
|
}
|
||
|
|
||
|
/******************************************************************
|
||
|
* cCondition
|
||
|
******************************************************************/
|
||
|
cCondition::cCondition(const char *expression) {
|
||
|
expr = strdup(expression);
|
||
|
globals = NULL;
|
||
|
tokenContainer = NULL;
|
||
|
loopInfo = NULL;
|
||
|
}
|
||
|
|
||
|
cCondition::cCondition(const cCondition &other) {
|
||
|
expr = strdup(other.expr);
|
||
|
globals = NULL;
|
||
|
tokenContainer = NULL;
|
||
|
loopInfo = NULL;
|
||
|
for (cCond *cond = other.conds.First(); cond; cond = other.conds.Next(cond))
|
||
|
conds.Add(new cCond(*cond));
|
||
|
}
|
||
|
|
||
|
cCondition::~cCondition(void) {
|
||
|
free(expr);
|
||
|
}
|
||
|
|
||
|
void cCondition::Prepare(void) {
|
||
|
expr = RemoveSpace(expr);
|
||
|
Tokenize();
|
||
|
PrepareTokens();
|
||
|
}
|
||
|
|
||
|
bool cCondition::True(void) {
|
||
|
if (conds.Count() == 0)
|
||
|
return true;
|
||
|
bool ok = true;
|
||
|
for (cCond *c = conds.First(); c; c = conds.Next(c)) {
|
||
|
bool condTrue = true;
|
||
|
//evaluate condition
|
||
|
if (c->constant)
|
||
|
{
|
||
|
condTrue = c->isTrue;
|
||
|
}
|
||
|
else if (c->type == eCondType::token)
|
||
|
{
|
||
|
if (c->tokenType == eCondTokenType::inttoken) {
|
||
|
int tokenVal = tokenContainer->IntToken(c->tokenIndex);
|
||
|
condTrue = (tokenVal > 0) ? true : false;
|
||
|
} else if (c->tokenType == eCondTokenType::stringtoken) {
|
||
|
char *tokenVal = tokenContainer->StringToken(c->tokenIndex);
|
||
|
if (tokenVal)
|
||
|
condTrue = (!strcmp(tokenVal, "1")) ? true : false;
|
||
|
} else if (c->tokenType == eCondTokenType::looptoken) {
|
||
|
if (loopInfo && loopInfo->row >= 0) {
|
||
|
char *tokenVal = tokenContainer->LoopToken(loopInfo->index, loopInfo->row, c->tokenIndex);
|
||
|
if (tokenVal)
|
||
|
condTrue = (!strcmp(tokenVal, "1")) ? true : false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if (c->type == eCondType::negtoken)
|
||
|
{
|
||
|
if (c->tokenType == eCondTokenType::inttoken) {
|
||
|
int tokenVal = tokenContainer->IntToken(c->tokenIndex);
|
||
|
condTrue = (tokenVal > 0) ? false : true;
|
||
|
} else if (c->tokenType == eCondTokenType::stringtoken) {
|
||
|
char *tokenVal = tokenContainer->StringToken(c->tokenIndex);
|
||
|
if (tokenVal)
|
||
|
condTrue = (!strcmp(tokenVal, "1")) ? false : true;
|
||
|
} else if (c->tokenType == eCondTokenType::looptoken) {
|
||
|
if (loopInfo && loopInfo->row >= 0) {
|
||
|
char *tokenVal = tokenContainer->LoopToken(loopInfo->index, loopInfo->row, c->tokenIndex);
|
||
|
if (tokenVal)
|
||
|
condTrue = (!strcmp(tokenVal, "1")) ? false : true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (c->type == eCondType::lowerInt || c->type == eCondType::equalInt || c->type == eCondType::greaterInt)
|
||
|
{
|
||
|
if (c->tokenType == eCondTokenType::inttoken) {
|
||
|
int tokenVal = tokenContainer->IntToken(c->tokenIndex);
|
||
|
if (c->type == eCondType::lowerInt)
|
||
|
condTrue = (tokenVal < c->compareValue) ? true : false;
|
||
|
else if (c->type == eCondType::equalInt)
|
||
|
condTrue = (tokenVal == c->compareValue) ? true : false;
|
||
|
else if (c->type == eCondType::greaterInt)
|
||
|
condTrue = (tokenVal > c->compareValue) ? true : false;
|
||
|
} else if (c->tokenType == eCondTokenType::stringtoken) {
|
||
|
char *tokenVal = tokenContainer->StringToken(c->tokenIndex);
|
||
|
if (tokenVal) {
|
||
|
int intVal = atoi(tokenVal);
|
||
|
if (c->type == eCondType::lowerInt)
|
||
|
condTrue = (intVal < c->compareValue) ? true : false;
|
||
|
else if (c->type == eCondType::equalInt)
|
||
|
condTrue = (intVal == c->compareValue) ? true : false;
|
||
|
else if (c->type == eCondType::greaterInt)
|
||
|
condTrue = (intVal > c->compareValue) ? true : false;
|
||
|
}
|
||
|
} else if (c->tokenType == eCondTokenType::looptoken) {
|
||
|
if (loopInfo && loopInfo->row >= 0) {
|
||
|
char *tokenVal = tokenContainer->LoopToken(loopInfo->index, loopInfo->row, c->tokenIndex);
|
||
|
if (tokenVal) {
|
||
|
int intVal = atoi(tokenVal);
|
||
|
if (c->type == eCondType::lowerInt)
|
||
|
condTrue = (intVal < c->compareValue) ? true : false;
|
||
|
else if (c->type == eCondType::equalInt)
|
||
|
condTrue = (intVal == c->compareValue) ? true : false;
|
||
|
else if (c->type == eCondType::greaterInt)
|
||
|
condTrue = (intVal > c->compareValue) ? true : false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (c->type == eCondType::isset || c->type == eCondType::empty)
|
||
|
{
|
||
|
if (c->tokenType == eCondTokenType::stringtoken) {
|
||
|
char *tokenVal = tokenContainer->StringToken(c->tokenIndex);
|
||
|
if (tokenVal) {
|
||
|
if (c->type == eCondType::isset)
|
||
|
condTrue = strlen(tokenVal) > 0 ? true : false;
|
||
|
else if (c->type == eCondType::empty)
|
||
|
condTrue = strlen(tokenVal) == 0 ? true : false;
|
||
|
} else {
|
||
|
if (c->type == eCondType::isset)
|
||
|
condTrue = false;
|
||
|
else if (c->type == eCondType::empty)
|
||
|
condTrue = true;
|
||
|
}
|
||
|
} else if (c->tokenType == eCondTokenType::looptoken) {
|
||
|
if (loopInfo && loopInfo->row >= 0) {
|
||
|
char *tokenVal = tokenContainer->LoopToken(loopInfo->index, loopInfo->row, c->tokenIndex);
|
||
|
if (tokenVal) {
|
||
|
if (c->type == eCondType::isset)
|
||
|
condTrue = strlen(tokenVal) > 0 ? true : false;
|
||
|
else if (c->type == eCondType::empty)
|
||
|
condTrue = strlen(tokenVal) == 0 ? true : false;
|
||
|
} else {
|
||
|
if (c->type == eCondType::isset)
|
||
|
condTrue = false;
|
||
|
else if (c->type == eCondType::empty)
|
||
|
condTrue = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (c->type == eCondType::equalString || c->type == eCondType::notEqualString || c->type == eCondType::contains || c->type == eCondType::notContains)
|
||
|
{
|
||
|
if (c->tokenType == eCondTokenType::stringtoken) {
|
||
|
char *tokenVal = tokenContainer->StringToken(c->tokenIndex);
|
||
|
if (tokenVal) {
|
||
|
if (c->type == eCondType::equalString)
|
||
|
condTrue = !strcmp(tokenVal, c->compareStrValue) ? true : false;
|
||
|
else if (c->type == eCondType::notEqualString)
|
||
|
condTrue = strcmp(tokenVal, c->compareStrValue) ? true : false;
|
||
|
else if (c->type == eCondType::contains)
|
||
|
condTrue = strstr(tokenVal, c->compareStrValue) ? true : false;
|
||
|
else if (c->type == eCondType::notContains)
|
||
|
condTrue = !strstr(tokenVal, c->compareStrValue) ? true : false;
|
||
|
}
|
||
|
} else if (c->tokenType == eCondTokenType::looptoken) {
|
||
|
if (loopInfo && loopInfo->row >= 0) {
|
||
|
char *tokenVal = tokenContainer->LoopToken(loopInfo->index, loopInfo->row, c->tokenIndex);
|
||
|
if (tokenVal) {
|
||
|
if (c->type == eCondType::equalString)
|
||
|
condTrue = !strcmp(tokenVal, c->compareStrValue) ? true : false;
|
||
|
else if (c->type == eCondType::notEqualString)
|
||
|
condTrue = strcmp(tokenVal, c->compareStrValue) ? true : false;
|
||
|
else if (c->type == eCondType::contains)
|
||
|
condTrue = strstr(tokenVal, c->compareStrValue) ? true : false;
|
||
|
else if (c->type == eCondType::notContains)
|
||
|
condTrue = !strstr(tokenVal, c->compareStrValue) ? true : false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} //link
|
||
|
if (c->operation == eCondOp::tAnd) {
|
||
|
ok = ok && condTrue;
|
||
|
} else if (c->operation == eCondOp::tOr) {
|
||
|
ok = ok || condTrue;
|
||
|
}
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
void cCondition::Debug(void) {
|
||
|
esyslog("skindesigner: condition \"%s\"", expr);
|
||
|
for (cCond *c = conds.First(); c; c = conds.Next(c)) {
|
||
|
c->Debug();
|
||
|
}
|
||
|
esyslog("skindesigner: condition is %s", True() ? "TRUE" : "FALSE");
|
||
|
}
|
||
|
|
||
|
void cCondition::Tokenize(void) {
|
||
|
char *condition = strdup(expr);
|
||
|
char delimiter[] = "+|";
|
||
|
eCondOp operation = eCondOp::tAnd;
|
||
|
|
||
|
char *cond = strtok(condition, delimiter);
|
||
|
while (cond) {
|
||
|
eCondType type = eCondType::token;
|
||
|
if (startswith(cond, "{") && endswith(cond, "}")) {
|
||
|
type = eCondType::token;
|
||
|
} else if (startswith(cond, "not{") && endswith(cond, "}")) {
|
||
|
type = eCondType::negtoken;
|
||
|
} else if (startswith(cond, "lt({") && endswith(cond, ")")) {
|
||
|
type = eCondType::lowerInt;
|
||
|
} else if (startswith(cond, "eq({") && endswith(cond, ")")) {
|
||
|
type = eCondType::equalInt;
|
||
|
} else if (startswith(cond, "gt({") && endswith(cond, ")")) {
|
||
|
type = eCondType::greaterInt;
|
||
|
} else if (startswith(cond, "isset{") && endswith(cond, "}")) {
|
||
|
type = eCondType::isset;
|
||
|
} else if (startswith(cond, "empty{") && endswith(cond, "}")) {
|
||
|
type = eCondType::empty;
|
||
|
} else if (startswith(cond, "strequal({") && endswith(cond, ")")) {
|
||
|
type = eCondType::equalString;
|
||
|
} else if (startswith(cond, "strnotequal({") && endswith(cond, ")")) {
|
||
|
type = eCondType::notEqualString;
|
||
|
} else if (startswith(cond, "strcontains({") && endswith(cond, ")")) {
|
||
|
type = eCondType::contains;
|
||
|
} else if (startswith(cond, "strnotcontains({") && endswith(cond, ")")) {
|
||
|
type = eCondType::notContains;
|
||
|
} else {
|
||
|
esyslog("skindesigner: invalid condition term %s", cond);
|
||
|
cond = strtok(NULL, delimiter);
|
||
|
continue;
|
||
|
}
|
||
|
cCond *c = new cCond(cond);
|
||
|
c->operation = operation;
|
||
|
c->type = type;
|
||
|
conds.Add(c);
|
||
|
if (expr[cond - condition + strlen(cond)] == '+')
|
||
|
operation = eCondOp::tAnd;
|
||
|
else
|
||
|
operation = eCondOp::tOr;
|
||
|
cond = strtok(NULL, delimiter);
|
||
|
}
|
||
|
free(condition);
|
||
|
}
|
||
|
|
||
|
void cCondition::PrepareTokens(void) {
|
||
|
for (cCond *c = conds.First(); c; c = conds.Next(c)) {
|
||
|
switch (c->type) {
|
||
|
case eCondType::token:
|
||
|
case eCondType::negtoken:
|
||
|
SetTokenCond(c);
|
||
|
break;
|
||
|
case eCondType::lowerInt:
|
||
|
case eCondType::equalInt:
|
||
|
case eCondType::greaterInt:
|
||
|
SetIntegerCond(c);
|
||
|
break;
|
||
|
case eCondType::isset:
|
||
|
case eCondType::empty:
|
||
|
SetStringCond(c);
|
||
|
break;
|
||
|
case eCondType::equalString:
|
||
|
case eCondType::notEqualString:
|
||
|
case eCondType::contains:
|
||
|
case eCondType::notContains:
|
||
|
SetStringCompareCond(c);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void cCondition::SetTokenCond(cCond *c) {
|
||
|
if (c->type == eCondType::negtoken) {
|
||
|
ReplaceStart(c->expr, 3);
|
||
|
}
|
||
|
//check globals
|
||
|
int result = 0;
|
||
|
string tmp = c->expr;
|
||
|
tmp = tmp.substr(1, tmp.size()-2);
|
||
|
if (globals->GetInt(tmp, result)) {
|
||
|
c->constant = true;
|
||
|
if (result == 1 && c->type == eCondType::token)
|
||
|
c->isTrue = true;
|
||
|
if (result == 0 && c->type == eCondType::negtoken)
|
||
|
c->isTrue = true;
|
||
|
return;
|
||
|
}
|
||
|
SetTokenIndex(c, c->expr);
|
||
|
}
|
||
|
|
||
|
void cCondition::SetIntegerCond(cCond *c) {
|
||
|
char *tokenStart = strchr(c->expr, '{');
|
||
|
char *tokenEnd = strchr(c->expr, '}');
|
||
|
if (!tokenStart || !tokenEnd)
|
||
|
return;
|
||
|
char token[200] = "";
|
||
|
strncpy(token, tokenStart, tokenEnd - tokenStart + 1);
|
||
|
|
||
|
char *condStart = strchr(c->expr, ',');
|
||
|
char *condEnd = strchr(c->expr, ')');
|
||
|
char strCond[100] = "";
|
||
|
strncpy(strCond, condStart + 1, condEnd - condStart - 1);
|
||
|
c->compareValue = atoi(strCond);
|
||
|
|
||
|
//check globals
|
||
|
int result = 0;
|
||
|
if (globals->GetInt(token, result)) {
|
||
|
c->constant = true;
|
||
|
if (c->type == eCondType::lowerInt && result < c->compareValue)
|
||
|
c->isTrue = true;
|
||
|
else if (c->type == eCondType::equalInt && result == c->compareValue)
|
||
|
c->isTrue = true;
|
||
|
else if (c->type == eCondType::greaterInt && result > c->compareValue)
|
||
|
c->isTrue = true;
|
||
|
return;
|
||
|
}
|
||
|
SetTokenIndex(c, token);
|
||
|
}
|
||
|
|
||
|
void cCondition::SetStringCond(cCond *c) {
|
||
|
ReplaceStart(c->expr, 5);
|
||
|
SetTokenIndex(c, c->expr);
|
||
|
}
|
||
|
|
||
|
void cCondition::SetStringCompareCond(cCond *c) {
|
||
|
char *tokenStart = strchr(c->expr, '{');
|
||
|
char *tokenEnd = strchr(c->expr, '}');
|
||
|
if (!tokenStart || !tokenEnd)
|
||
|
return;
|
||
|
char token[200] = "";
|
||
|
strncpy(token, tokenStart, tokenEnd - tokenStart + 1);
|
||
|
|
||
|
char *condStart = strstr(c->expr, ",'");
|
||
|
char *condEnd = strstr(c->expr, "')");
|
||
|
char strCond[100] = "";
|
||
|
strncpy(strCond, condStart + 2, condEnd - condStart - 2);
|
||
|
c->compareStrValue = strdup(strCond);
|
||
|
SetTokenIndex(c, token);
|
||
|
}
|
||
|
|
||
|
void cCondition::SetTokenIndex(cCond *c, const char *token) {
|
||
|
int tokenIndex = tokenContainer->IntTokenIndex(token);
|
||
|
if (tokenIndex >= 0) {
|
||
|
c->tokenIndex = tokenIndex;
|
||
|
c->tokenType = eCondTokenType::inttoken;
|
||
|
return;
|
||
|
}
|
||
|
tokenIndex = tokenContainer->StringTokenIndex(token);
|
||
|
if (tokenIndex >= 0) {
|
||
|
c->tokenIndex = tokenIndex;
|
||
|
c->tokenType = eCondTokenType::stringtoken;
|
||
|
return;
|
||
|
}
|
||
|
tokenIndex = tokenContainer->LoopTokenIndex(token);
|
||
|
if (tokenIndex >= 0) {
|
||
|
c->tokenIndex = tokenIndex;
|
||
|
c->tokenType = eCondTokenType::looptoken;
|
||
|
}
|
||
|
}
|
||
|
/******************************************************************
|
||
|
* cSummand
|
||
|
******************************************************************/
|
||
|
cSummand::cSummand(const char *summand) {
|
||
|
this->summand = strdup(summand);
|
||
|
}
|
||
|
|
||
|
cSummand::cSummand(const cSummand &other) {
|
||
|
summand = NULL;
|
||
|
if (other.summand)
|
||
|
summand = strdup(other.summand);
|
||
|
positive = other.positive;
|
||
|
for (cFactor *fac = other.factors.First(); fac; fac = other.factors.Next(fac)) {
|
||
|
factors.Add(new cFactor(*fac));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cSummand::~cSummand(void) {
|
||
|
free(summand);
|
||
|
}
|
||
|
|
||
|
void cSummand::Debug(void) {
|
||
|
esyslog("skindesigner: summand %s, positive: %d", summand, positive);
|
||
|
for (cFactor *f = factors.First(); f; f = factors.Next(f)) {
|
||
|
const char *link = f->multiplication ? "multiplication" : "division";
|
||
|
if (f->type == eFactorType::constant)
|
||
|
esyslog("skindesigner: constant factor %f, %s", f->constValue, link);
|
||
|
else if (f->type == eFactorType::inttoken)
|
||
|
esyslog("skindesigner: IntToken factor, index %d, %s", f->tokenIndex, link);
|
||
|
else if (f->type == eFactorType::stringtoken)
|
||
|
esyslog("skindesigner: StringToken factor, index %d, %s", f->tokenIndex, link);
|
||
|
else if (f->type == eFactorType::looptoken)
|
||
|
esyslog("skindesigner: LoopToken factor, index %d, %s", f->tokenIndex, link);
|
||
|
else if (f->type == eFactorType::xref)
|
||
|
esyslog("skindesigner: posx reference factor, %s, %p, %s, result: %f", f->funcRefName, f->funcRef, link, f->funcRef->FuncX());
|
||
|
else if (f->type == eFactorType::yref)
|
||
|
esyslog("skindesigner: posy reference factor, %s, %p, %s, result: %f", f->funcRefName, f->funcRef, link, f->funcRef->FuncY());
|
||
|
else if (f->type == eFactorType::widthref)
|
||
|
esyslog("skindesigner: width reference factor, %s, %p, %s, result: %f", f->funcRefName, f->funcRef, link, f->funcRef->FuncWidth());
|
||
|
else if (f->type == eFactorType::heightref)
|
||
|
esyslog("skindesigner: height reference factor, %s, %p %s, result: %f", f->funcRefName, f->funcRef, link, f->funcRef->FuncHeight());
|
||
|
else if (f->type == eFactorType::areawidth)
|
||
|
esyslog("skindesigner: {areawidth} factor, %s", link);
|
||
|
else if (f->type == eFactorType::areaheight)
|
||
|
esyslog("skindesigner: {areaheight} factor, %s", link);
|
||
|
else if (f->type == eFactorType::columnwidth)
|
||
|
esyslog("skindesigner: {columnwidth} factor, %s", link);
|
||
|
else if (f->type == eFactorType::rowheight)
|
||
|
esyslog("skindesigner: {rowheight} factor, %s", link);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************
|
||
|
* cNumericExpr
|
||
|
******************************************************************/
|
||
|
cNumericExpr::cNumericExpr(const char *expression) {
|
||
|
expr = strdup(expression);
|
||
|
globals = NULL;
|
||
|
container = NULL;
|
||
|
tokenContainer = NULL;
|
||
|
loopInfo = NULL;
|
||
|
horizontal = true;
|
||
|
value = 0;
|
||
|
dynamic = false;
|
||
|
}
|
||
|
|
||
|
cNumericExpr::cNumericExpr(const cNumericExpr &other) {
|
||
|
expr = strdup(other.expr);
|
||
|
globals = other.globals;
|
||
|
container = NULL;
|
||
|
tokenContainer = NULL;
|
||
|
loopInfo = NULL;
|
||
|
horizontal = other.horizontal;
|
||
|
value = other.value;
|
||
|
dynamic = other.dynamic;
|
||
|
for (cSummand *s = other.summands.First(); s; s = other.summands.Next(s)) {
|
||
|
summands.Add(new cSummand(*s));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cNumericExpr::~cNumericExpr(void) {
|
||
|
free(expr);
|
||
|
}
|
||
|
|
||
|
/******************************************************************
|
||
|
* Public Functions
|
||
|
******************************************************************/
|
||
|
bool cNumericExpr::CacheStatic(void) {
|
||
|
expr = RemoveSpace(expr);
|
||
|
if (config.replaceDecPoint)
|
||
|
ReplaceDecimalpoint(expr);
|
||
|
|
||
|
//first check if expression is already an valid integer
|
||
|
if (IsNumeric(expr)) {
|
||
|
value = atoi(expr);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//check if expression is a percent expression
|
||
|
if (PercentValue(expr)) {
|
||
|
return true;
|
||
|
}
|
||
|
//if areawidth or height unknown, percent values have to be replaced
|
||
|
expr = ReplacePercentValue(expr);
|
||
|
//replace {areawidth} and {areaheight}
|
||
|
if (container->Width() >= 0) {
|
||
|
//esyslog("skindesigner: replacing areawidth %s", expr);
|
||
|
expr = ReplaceTokens(expr, "{areawidth}", container->Width());
|
||
|
//esyslog("skindesigner: replaced areawidth %s", expr);
|
||
|
}
|
||
|
if (container->Height() >= 0)
|
||
|
expr = ReplaceTokens(expr, "{areaheight}", container->Height());
|
||
|
|
||
|
//replace globals
|
||
|
string tmp = expr;
|
||
|
globals->ReplaceIntVars(tmp);
|
||
|
globals->ReplaceDoubleVars(tmp);
|
||
|
free(expr);
|
||
|
expr = strdup(tmp.c_str());
|
||
|
if (IsNumeric(expr)) {
|
||
|
value = atoi(expr);
|
||
|
return true;
|
||
|
}
|
||
|
//check if all variables are eliminated
|
||
|
if (IsNumericExpression(expr)) {
|
||
|
value = EvaluateExpression(expr);
|
||
|
return true;
|
||
|
}
|
||
|
//now we have a expression with runtime variables
|
||
|
dynamic = true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void cNumericExpr::PrepareTokens(void) {
|
||
|
CreateSummands();
|
||
|
CreateFactors();
|
||
|
ConsolidateFactors();
|
||
|
ConsolidateSummand();
|
||
|
}
|
||
|
|
||
|
vector<cFactor*> cNumericExpr::GetRefFactors(void) {
|
||
|
vector<cFactor*> refFactors;
|
||
|
for (cSummand *s = summands.First(); s; s = summands.Next(s)) {
|
||
|
for (cFactor* f = s->factors.First(); f; f = s->factors.Next(f)) {
|
||
|
if (f->type >= eFactorType::xref) {
|
||
|
refFactors.push_back(f);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return refFactors;
|
||
|
}
|
||
|
|
||
|
int cNumericExpr::Calculate(void) {
|
||
|
double result = 0.0f;
|
||
|
for (cSummand *s = summands.First(); s; s = summands.Next(s)) {
|
||
|
double factor = 1.0f;
|
||
|
for (cFactor *f = s->factors.First(); f; f = s->factors.Next(f)) {
|
||
|
double fac = 0.0f;
|
||
|
switch( f->type ) {
|
||
|
case eFactorType::constant:
|
||
|
fac = f->constValue;
|
||
|
break;
|
||
|
case eFactorType::stringtoken: {
|
||
|
char *val = tokenContainer->StringToken(f->tokenIndex);
|
||
|
if (val)
|
||
|
fac = atoi(val);
|
||
|
break; }
|
||
|
case eFactorType::inttoken:
|
||
|
fac = tokenContainer->IntToken(f->tokenIndex);
|
||
|
break;
|
||
|
case eFactorType::looptoken:
|
||
|
if (loopInfo && loopInfo->row >= 0) {
|
||
|
char *val = tokenContainer->LoopToken(loopInfo->index, loopInfo->row, f->tokenIndex);
|
||
|
if (val)
|
||
|
fac = atoi(val);
|
||
|
}
|
||
|
break;
|
||
|
case eFactorType::xref:
|
||
|
if (f->funcRef)
|
||
|
fac = f->funcRef->FuncX();
|
||
|
break;
|
||
|
case eFactorType::yref:
|
||
|
if (f->funcRef)
|
||
|
fac = f->funcRef->FuncY();
|
||
|
break;
|
||
|
case eFactorType::widthref:
|
||
|
if (f->funcRef)
|
||
|
fac = f->funcRef->FuncWidth();
|
||
|
break;
|
||
|
case eFactorType::heightref:
|
||
|
if (f->funcRef)
|
||
|
fac = f->funcRef->FuncHeight();
|
||
|
break;
|
||
|
case eFactorType::areawidth:
|
||
|
fac = container->Width();
|
||
|
break;
|
||
|
case eFactorType::areaheight:
|
||
|
fac = container->Height();
|
||
|
break;
|
||
|
case eFactorType::columnwidth:
|
||
|
if (loopInfo)
|
||
|
fac = loopInfo->colWidth;
|
||
|
break;
|
||
|
case eFactorType::rowheight:
|
||
|
if (loopInfo)
|
||
|
fac = loopInfo->rowHeight;
|
||
|
break;
|
||
|
}
|
||
|
if (f->multiplication)
|
||
|
factor *= fac;
|
||
|
else if (fac)
|
||
|
factor /= fac;
|
||
|
}
|
||
|
if (s->positive)
|
||
|
result += factor;
|
||
|
else
|
||
|
result -= factor;
|
||
|
}
|
||
|
return (int)result;
|
||
|
}
|
||
|
|
||
|
|
||
|
void cNumericExpr::Debug(void) {
|
||
|
esyslog("skindesigner: Numeric Expression \"%s\", Result: %d", expr, Calculate());
|
||
|
for (cSummand *s = summands.First(); s; s = summands.Next(s)) {
|
||
|
s->Debug();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************
|
||
|
* Private Functions
|
||
|
******************************************************************/
|
||
|
bool cNumericExpr::IsNumeric(const char *e) {
|
||
|
//negativ numbers
|
||
|
if (*e == '-')
|
||
|
++e;
|
||
|
//empty
|
||
|
if (!*e)
|
||
|
return false;
|
||
|
while (*e) {
|
||
|
if (isdigit(*e) || *e == '.' || *e == ',')
|
||
|
++e;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool cNumericExpr::IsNumericExpression(const char *e) {
|
||
|
if (!*e)
|
||
|
return false;
|
||
|
while (*e) {
|
||
|
if (isdigit(*e) || *e == '.' || *e == ',' || *e == '+' || *e == '-' || *e == '*' || *e == '/')
|
||
|
++e;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool cNumericExpr::PercentValue(const char *e) {
|
||
|
const char *hit = strchr(e, '%');
|
||
|
if (!hit)
|
||
|
return false;
|
||
|
char buffer[20] = "";
|
||
|
if (strlen(e) > 20)
|
||
|
return false;
|
||
|
strncpy(buffer, e, strlen(e)-1);
|
||
|
buffer[strlen(e)-1] = '\0';
|
||
|
int val = atoi(buffer);
|
||
|
bool ok = false;
|
||
|
if (horizontal && container->Width() > 0) {
|
||
|
value = container->Width() * val / 100;
|
||
|
ok = true;
|
||
|
} else if (!horizontal && container->Height() > 0){
|
||
|
value = container->Height() * val / 100;
|
||
|
ok = true;
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
char *cNumericExpr::ReplacePercentValue(char *e) {
|
||
|
const char *hit = strchr(e, '%');
|
||
|
if (!hit)
|
||
|
return e;
|
||
|
char buffer[20] = "";
|
||
|
if (strlen(e) > 20)
|
||
|
return e;
|
||
|
strncpy(buffer, e, strlen(e)-1);
|
||
|
buffer[strlen(e)-1] = '\0';
|
||
|
int val = atoi(buffer);
|
||
|
double percentVal = (double)val/100.0f;
|
||
|
|
||
|
char replacement[50] = "";
|
||
|
if (horizontal) {
|
||
|
sprintf(replacement, "%.5f*{areawidth}", percentVal);
|
||
|
} else {
|
||
|
sprintf(replacement, "%.5f*{areaheight}", percentVal);
|
||
|
}
|
||
|
|
||
|
int len = strlen(replacement) + 1;
|
||
|
char *replaced = (char*)malloc(len);
|
||
|
memset(replaced, 0, len);
|
||
|
strcpy(replaced, replacement);
|
||
|
free(expr);
|
||
|
return replaced;
|
||
|
}
|
||
|
|
||
|
char *cNumericExpr::ReplaceToken(char *e, const char* token, int val) {
|
||
|
char *tokenStart = strstr(e, token);
|
||
|
if (!tokenStart) {
|
||
|
return e;
|
||
|
}
|
||
|
char buffer[20] = "";
|
||
|
sprintf(buffer, "%d", val);
|
||
|
size_t newSize = strlen(e) - strlen(token) + strlen(buffer) + 1;
|
||
|
char *replaced = (char*)malloc(newSize);
|
||
|
memset(replaced, 0, newSize);
|
||
|
size_t beginning = strlen(e) - strlen(tokenStart);
|
||
|
if (beginning > 0)
|
||
|
strncpy(replaced, e, beginning);
|
||
|
strcat(replaced, buffer);
|
||
|
strcat(replaced, tokenStart + strlen(token));
|
||
|
free(e);
|
||
|
return replaced;
|
||
|
}
|
||
|
|
||
|
char *cNumericExpr::ReplaceTokens(char *e, const char* token, int val) {
|
||
|
if (!e)
|
||
|
return e;
|
||
|
while (true) {
|
||
|
char *tokenStart = strstr(e, token);
|
||
|
if (!tokenStart)
|
||
|
break;
|
||
|
e = ReplaceToken(e, token, val);
|
||
|
}
|
||
|
return e;
|
||
|
}
|
||
|
|
||
|
int cNumericExpr::EvaluateExpression(char* e) {
|
||
|
return round(ParseSummands(e));
|
||
|
}
|
||
|
|
||
|
double cNumericExpr::EvaluateExpressionDouble(char *e) {
|
||
|
return ParseSummands(e);
|
||
|
}
|
||
|
|
||
|
double cNumericExpr::ParseAtom(char*& e) {
|
||
|
// Read the number from string
|
||
|
char* end_ptr;
|
||
|
double res = strtod(e, &end_ptr);
|
||
|
// Advance the pointer and return the result
|
||
|
e = end_ptr;
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
// Parse multiplication and division
|
||
|
double cNumericExpr::ParseFactors(char*& e) {
|
||
|
double num1 = ParseAtom(e);
|
||
|
for(;;) {
|
||
|
// Save the operation
|
||
|
char op = *e;
|
||
|
if(op != '/' && op != '*')
|
||
|
return num1;
|
||
|
e++;
|
||
|
double num2 = ParseAtom(e);
|
||
|
// Perform the saved operation
|
||
|
if(op == '/') {
|
||
|
if (num2 != 0) {
|
||
|
num1 /= num2;
|
||
|
}
|
||
|
} else
|
||
|
num1 *= num2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Parse addition and subtraction
|
||
|
double cNumericExpr::ParseSummands(char*& e) {
|
||
|
double num1 = ParseFactors(e);
|
||
|
for(;;) {
|
||
|
char op = *e;
|
||
|
if(op != '-' && op != '+')
|
||
|
return num1;
|
||
|
e++;
|
||
|
double num2 = ParseFactors(e);
|
||
|
if(op == '-')
|
||
|
num1 -= num2;
|
||
|
else
|
||
|
num1 += num2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void cNumericExpr::CreateSummands(void) {
|
||
|
char *sum = strdup(expr);
|
||
|
char delimiter[] = "+-";
|
||
|
bool positive = true;
|
||
|
if (sum && *sum && *sum == '-') {
|
||
|
positive = false;
|
||
|
}
|
||
|
char *summand = strtok(sum, delimiter);
|
||
|
while (summand) {
|
||
|
cSummand *s = new cSummand(summand);
|
||
|
s->positive = positive;
|
||
|
summands.Add(s);
|
||
|
//check next sign
|
||
|
if (expr[summand - sum + strlen(summand)] == '-')
|
||
|
positive = false;
|
||
|
else
|
||
|
positive = true;
|
||
|
summand = strtok(NULL, delimiter);
|
||
|
}
|
||
|
free(sum);
|
||
|
}
|
||
|
|
||
|
void cNumericExpr::CreateFactors(void) {
|
||
|
char delimiterFac[] = "*/";
|
||
|
for (cSummand *s = summands.First(); s; s = summands.Next(s)) {
|
||
|
char *sum = strdup(s->summand);
|
||
|
if (IsNumericExpression(sum)) {
|
||
|
cFactor *f = new cFactor();
|
||
|
f->constValue = EvaluateExpressionDouble(sum);
|
||
|
s->factors.Add(f);
|
||
|
free(sum);
|
||
|
continue;
|
||
|
}
|
||
|
bool multiplication = true;
|
||
|
char *fac = strtok(sum, delimiterFac);
|
||
|
while (fac) {
|
||
|
cFactor *f = new cFactor();
|
||
|
if (IsNumeric(fac)) {
|
||
|
f->constValue = atof(fac);
|
||
|
f->multiplication = multiplication;
|
||
|
s->factors.Add(f);
|
||
|
} else {
|
||
|
//factor has to be a token or a function reference now
|
||
|
if (SetTokenFactor(f, fac)) {
|
||
|
f->multiplication = multiplication;
|
||
|
s->factors.Add(f);
|
||
|
} else if (SetReferenceFactor(f, fac)) {
|
||
|
f->multiplication = multiplication;
|
||
|
s->factors.Add(f);
|
||
|
} else if (SetGeometryFactor(f, fac)) {
|
||
|
f->multiplication = multiplication;
|
||
|
s->factors.Add(f);
|
||
|
} else {
|
||
|
esyslog("skindesigner: invalid factor %s in expression \"%s\"", fac, expr);
|
||
|
delete f;
|
||
|
}
|
||
|
}
|
||
|
//check next sign
|
||
|
if (s->summand[fac - sum + strlen(fac)] == '/')
|
||
|
multiplication = false;
|
||
|
else
|
||
|
multiplication = true;
|
||
|
fac = strtok(NULL, delimiterFac);
|
||
|
}
|
||
|
free(sum);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool cNumericExpr::SetTokenFactor(cFactor *f, char *tokenName) {
|
||
|
int tokenIndex = tokenContainer->IntTokenIndex(tokenName);
|
||
|
if (tokenIndex >= 0) {
|
||
|
f->tokenIndex = tokenIndex;
|
||
|
f->type = eFactorType::inttoken;
|
||
|
return true;
|
||
|
}
|
||
|
tokenIndex = tokenContainer->StringTokenIndex(tokenName);
|
||
|
if (tokenIndex >= 0) {
|
||
|
f->tokenIndex = tokenIndex;
|
||
|
f->type = eFactorType::stringtoken;
|
||
|
return true;
|
||
|
}
|
||
|
tokenIndex = tokenContainer->LoopTokenIndex(tokenName);
|
||
|
if (tokenIndex >= 0) {
|
||
|
f->tokenIndex = tokenIndex;
|
||
|
f->type = eFactorType::looptoken;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool cNumericExpr::SetReferenceFactor(cFactor *f, char *tokenName) {
|
||
|
int start = 0;
|
||
|
if (startswith(tokenName, "{posx(") && endswith(tokenName, ")}")) {
|
||
|
start = 6;
|
||
|
f->type = eFactorType::xref;
|
||
|
} else if (startswith(tokenName, "{posy(") && endswith(tokenName, ")}")) {
|
||
|
start = 6;
|
||
|
f->type = eFactorType::yref;
|
||
|
} else if (startswith(tokenName, "{width(") && endswith(tokenName, ")}")) {
|
||
|
start = 7;
|
||
|
f->type = eFactorType::widthref;
|
||
|
} else if (startswith(tokenName, "{height(") && endswith(tokenName, ")}")) {
|
||
|
start = 8;
|
||
|
f->type = eFactorType::heightref;
|
||
|
}
|
||
|
|
||
|
if (start == 0)
|
||
|
return false;
|
||
|
|
||
|
tokenName += start;
|
||
|
f->funcRefName = strdup(tokenName);
|
||
|
ReplaceEnd(f->funcRefName, 2);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool cNumericExpr::SetGeometryFactor(cFactor *f, char *tokenName) {
|
||
|
bool ok = false;
|
||
|
if (!strcmp(tokenName, "{areawidth}")) {
|
||
|
f->type = eFactorType::areawidth;
|
||
|
ok = true;
|
||
|
} else if (!strcmp(tokenName, "{areaheight}")) {
|
||
|
f->type = eFactorType::areaheight;
|
||
|
ok = true;
|
||
|
} else if (!strcmp(tokenName, "{columnwidth}")) {
|
||
|
f->type = eFactorType::columnwidth;
|
||
|
ok = true;
|
||
|
} else if (!strcmp(tokenName, "{rowheight}")) {
|
||
|
f->type = eFactorType::rowheight;
|
||
|
ok = true;
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
void cNumericExpr::ConsolidateSummand(void) {
|
||
|
cSummand *constSummand = NULL;
|
||
|
for (cSummand *s = summands.First(); s; s = summands.Next(s)) {
|
||
|
if (s->factors.Count() == 1 && s->factors.First()->type == eFactorType::constant) {
|
||
|
if (!constSummand) {
|
||
|
constSummand = s;
|
||
|
} else {
|
||
|
if (s->positive)
|
||
|
constSummand->factors.First()->constValue += s->factors.First()->constValue;
|
||
|
else
|
||
|
constSummand->factors.First()->constValue -= s->factors.First()->constValue;
|
||
|
summands.Del(s);
|
||
|
s = constSummand;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void cNumericExpr::ConsolidateFactors(void) {
|
||
|
for (cSummand *s = summands.First(); s; s = summands.Next(s)) {
|
||
|
cFactor *constFactor = NULL;
|
||
|
for (cFactor *f = s->factors.First(); f; f = s->factors.Next(f)) {
|
||
|
if (f->type == eFactorType::constant) {
|
||
|
if (!constFactor) {
|
||
|
constFactor = f;
|
||
|
} else {
|
||
|
if (f->multiplication)
|
||
|
constFactor->constValue *= f->constValue;
|
||
|
else
|
||
|
constFactor->constValue /= f->constValue;
|
||
|
s->factors.Del(f);
|
||
|
f = constFactor;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************
|
||
|
* cColor
|
||
|
******************************************************************/
|
||
|
cColor::cColor(const char *expression) {
|
||
|
globals = NULL;
|
||
|
expr = strdup(expression);
|
||
|
value = 0x00;
|
||
|
}
|
||
|
|
||
|
cColor::cColor(const cColor &other) {
|
||
|
globals = other.globals;
|
||
|
expr = strdup(other.expr);
|
||
|
value = other.value;
|
||
|
}
|
||
|
|
||
|
cColor::~cColor(void) {
|
||
|
free(expr);
|
||
|
}
|
||
|
|
||
|
void cColor::Cache(void) {
|
||
|
tColor colVal = 0x00;
|
||
|
string tmp = expr;
|
||
|
if (globals->GetColor(tmp, colVal)) {
|
||
|
value = colVal;
|
||
|
return;
|
||
|
}
|
||
|
if (strlen(expr) != 8)
|
||
|
return;
|
||
|
std::stringstream str;
|
||
|
str << tmp;
|
||
|
colVal = 0x00;
|
||
|
str >> std::hex >> colVal;
|
||
|
value = colVal;
|
||
|
}
|
||
|
|
||
|
tColor cColor::Color(void) {
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
void cColor::Debug(void) {
|
||
|
esyslog("skindesigner: Color \"%s\", Value %x", expr, value);
|
||
|
}
|
||
|
|
||
|
/******************************************************************
|
||
|
* cTextExpr
|
||
|
******************************************************************/
|
||
|
cTextExpr::cTextExpr(const char *expression) {
|
||
|
globals = NULL;
|
||
|
expr = strdup(expression);
|
||
|
tokenContainer = NULL;
|
||
|
loopInfo = NULL;
|
||
|
}
|
||
|
|
||
|
cTextExpr::cTextExpr(const cTextExpr &other) {
|
||
|
globals = other.globals;
|
||
|
expr = strdup(other.expr);
|
||
|
tokenContainer = NULL;
|
||
|
loopInfo = NULL;
|
||
|
for (cTextToken* t = other.textTokens.First(); t; t = other.textTokens.Next(t)) {
|
||
|
textTokens.Add(new cTextToken(*t));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cTextExpr::~cTextExpr(void) {
|
||
|
free(expr);
|
||
|
}
|
||
|
|
||
|
void cTextExpr::CorrectImagePath(void) {
|
||
|
//no absolute pathes allowed
|
||
|
if (!startswith(expr, "{")) {
|
||
|
esyslog("skindesigner: no absolute pathes allowed for images - %s", expr);
|
||
|
}
|
||
|
if (startswith(expr, "{ressourcedir}")) {
|
||
|
string tmp = expr;
|
||
|
tmp = tmp.replace(0, 14, *config.GetSkinRessourcePath());
|
||
|
free(expr);
|
||
|
expr = strdup(tmp.c_str());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void cTextExpr::Cache(void) {
|
||
|
Translate();
|
||
|
Tokenize();
|
||
|
PrepareTokens();
|
||
|
}
|
||
|
|
||
|
char *cTextExpr::DeterminateText(void) {
|
||
|
//calculate length of complete new string
|
||
|
int textLength = 0;
|
||
|
for (cTextToken* t = textTokens.First(); t; t = textTokens.Next(t)) {
|
||
|
if (t->type == eTexttokenType::constant) {
|
||
|
textLength += strlen(t->constValue);
|
||
|
} else if (t->type == eTexttokenType::stringtoken) {
|
||
|
char *str = tokenContainer->StringToken(t->tokenIndex);
|
||
|
if (str)
|
||
|
textLength += strlen(str);
|
||
|
} else if (t->type == eTexttokenType::inttoken) {
|
||
|
int value = tokenContainer->IntToken(t->tokenIndex);
|
||
|
if (value >= 0) {
|
||
|
cString str = cString::sprintf("%d", value);
|
||
|
textLength += strlen(*str);
|
||
|
}
|
||
|
} else if (t->type == eTexttokenType::looptoken && loopInfo && loopInfo->row >= 0) {
|
||
|
char *str = tokenContainer->LoopToken(loopInfo->index, loopInfo->row, t->tokenIndex);
|
||
|
if (str)
|
||
|
textLength += strlen(str);
|
||
|
} else if (t->type == eTexttokenType::printftoken) {
|
||
|
DeterminatePrintfToken(t);
|
||
|
if (t->printfResult)
|
||
|
textLength += strlen(t->printfResult);
|
||
|
} else if (t->type == eTexttokenType::condstringtoken) {
|
||
|
char *str = tokenContainer->StringToken(t->tokenIndex);
|
||
|
if (str) {
|
||
|
textLength += strlen(str);
|
||
|
if (t->condStart)
|
||
|
textLength += strlen(t->condStart);
|
||
|
if (t->condEnd)
|
||
|
textLength += strlen(t->condEnd);
|
||
|
}
|
||
|
} else if (t->type == eTexttokenType::condinttoken) {
|
||
|
int value = tokenContainer->IntToken(t->tokenIndex);
|
||
|
if (value >= 0) {
|
||
|
cString str = cString::sprintf("%d", value);
|
||
|
textLength += strlen(*str);
|
||
|
if (t->condStart)
|
||
|
textLength += strlen(t->condStart);
|
||
|
if (t->condEnd)
|
||
|
textLength += strlen(t->condEnd);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (textLength <= 0)
|
||
|
return NULL;
|
||
|
|
||
|
char *retVal = (char*)malloc(textLength+1);
|
||
|
memset(retVal, 0, textLength);
|
||
|
bool first = true;
|
||
|
for (cTextToken* t = textTokens.First(); t; t = textTokens.Next(t)) {
|
||
|
if (first) {
|
||
|
first = false;
|
||
|
if (t->type == eTexttokenType::constant) {
|
||
|
strcpy(retVal, t->constValue);
|
||
|
} else if (t->type == eTexttokenType::stringtoken) {
|
||
|
char *str = tokenContainer->StringToken(t->tokenIndex);
|
||
|
if (str)
|
||
|
strcpy(retVal, str);
|
||
|
} else if (t->type == eTexttokenType::inttoken) {
|
||
|
int value = tokenContainer->IntToken(t->tokenIndex);
|
||
|
if (value >= 0) {
|
||
|
cString str = cString::sprintf("%d", value);
|
||
|
strcpy(retVal, *str);
|
||
|
}
|
||
|
} else if (t->type == eTexttokenType::looptoken && loopInfo && loopInfo->row >= 0) {
|
||
|
char *str = tokenContainer->LoopToken(loopInfo->index, loopInfo->row, t->tokenIndex);
|
||
|
if (str)
|
||
|
strcpy(retVal, str);
|
||
|
} else if (t->type == eTexttokenType::printftoken) {
|
||
|
if (t->printfResult) {
|
||
|
strcpy(retVal, t->printfResult);
|
||
|
free(t->printfResult);
|
||
|
t->printfResult = NULL;
|
||
|
}
|
||
|
} else if (t->type == eTexttokenType::condstringtoken) {
|
||
|
char *str = tokenContainer->StringToken(t->tokenIndex);
|
||
|
if (str) {
|
||
|
if (t->condStart) {
|
||
|
strcpy(retVal, t->condStart);
|
||
|
strcat(retVal, str);
|
||
|
} else {
|
||
|
strcpy(retVal, str);
|
||
|
}
|
||
|
if (t->condEnd)
|
||
|
strcat(retVal, t->condEnd);
|
||
|
}
|
||
|
} else if (t->type == eTexttokenType::condinttoken) {
|
||
|
int value = tokenContainer->IntToken(t->tokenIndex);
|
||
|
if (value >= 0) {
|
||
|
cString str = cString::sprintf("%d", value);
|
||
|
if (t->condStart) {
|
||
|
strcpy(retVal, t->condStart);
|
||
|
strcat(retVal, *str);
|
||
|
} else {
|
||
|
strcpy(retVal, *str);
|
||
|
}
|
||
|
if (t->condEnd)
|
||
|
strcat(retVal, t->condEnd);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if (t->type == eTexttokenType::constant) {
|
||
|
strcat(retVal, t->constValue);
|
||
|
} else if (t->type == eTexttokenType::stringtoken) {
|
||
|
char *str = tokenContainer->StringToken(t->tokenIndex);
|
||
|
if (str)
|
||
|
strcat(retVal, str);
|
||
|
} else if (t->type == eTexttokenType::inttoken) {
|
||
|
int value = tokenContainer->IntToken(t->tokenIndex);
|
||
|
cString str = cString::sprintf("%d", value);
|
||
|
strcat(retVal, *str);
|
||
|
} else if (t->type == eTexttokenType::looptoken && loopInfo && loopInfo->row >= 0) {
|
||
|
char *str = tokenContainer->LoopToken(loopInfo->index, loopInfo->row, t->tokenIndex);
|
||
|
if (str)
|
||
|
strcat(retVal, str);
|
||
|
} else if (t->type == eTexttokenType::printftoken) {
|
||
|
if (t->printfResult) {
|
||
|
strcat(retVal, t->printfResult);
|
||
|
free(t->printfResult);
|
||
|
t->printfResult = NULL;
|
||
|
}
|
||
|
} else if (t->type == eTexttokenType::condstringtoken) {
|
||
|
char *str = tokenContainer->StringToken(t->tokenIndex);
|
||
|
if (str) {
|
||
|
if (t->condStart)
|
||
|
strcat(retVal, t->condStart);
|
||
|
strcat(retVal, str);
|
||
|
if (t->condEnd)
|
||
|
strcat(retVal, t->condEnd);
|
||
|
}
|
||
|
} else if (t->type == eTexttokenType::condinttoken) {
|
||
|
int value = tokenContainer->IntToken(t->tokenIndex);
|
||
|
if (value >= 0) {
|
||
|
cString str = cString::sprintf("%d", value);
|
||
|
if (t->condStart)
|
||
|
strcat(retVal, t->condStart);
|
||
|
strcat(retVal, *str);
|
||
|
if (t->condEnd)
|
||
|
strcat(retVal, t->condEnd);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return retVal;
|
||
|
}
|
||
|
|
||
|
|
||
|
void cTextExpr::Debug(const char *exprName) {
|
||
|
esyslog("skindesigner: TextExpr %s: \"%s\"", exprName, expr);
|
||
|
char *res = DeterminateText();
|
||
|
esyslog("skindesigner: Result: \"%s\"", res);
|
||
|
free(res);
|
||
|
for (cTextToken *t = textTokens.First(); t; t = textTokens.Next(t)) {
|
||
|
if (t->type == eTexttokenType::constant)
|
||
|
esyslog("skindesigner: constant token \"%s\"", t->constValue);
|
||
|
else if (t->type == eTexttokenType::stringtoken)
|
||
|
esyslog("skindesigner: string token %s, index %d", t->constValue, t->tokenIndex);
|
||
|
else if (t->type == eTexttokenType::inttoken)
|
||
|
esyslog("skindesigner: int token %s, index %d", t->constValue, t->tokenIndex);
|
||
|
else if (t->type == eTexttokenType::looptoken)
|
||
|
esyslog("skindesigner: loop token %s, index %d", t->constValue, t->tokenIndex);
|
||
|
else if (t->type == eTexttokenType::printftoken)
|
||
|
esyslog("skindesigner: printf token %s", t->constValue);
|
||
|
else if (t->type == eTexttokenType::condstringtoken || t->type == eTexttokenType::condinttoken)
|
||
|
esyslog("skindesigner: conditional token %s", t->constValue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void cTextExpr::Translate(void) {
|
||
|
string translated = "";
|
||
|
if (!globals->Translate(expr, translated))
|
||
|
return;
|
||
|
free(expr);
|
||
|
expr = strdup(translated.c_str());
|
||
|
}
|
||
|
|
||
|
void cTextExpr::Tokenize(void) {
|
||
|
char *head = expr;
|
||
|
char *tail = expr;
|
||
|
while (*tail) {
|
||
|
if (*tail == '|') {
|
||
|
char *begin = CopyTextPart(head, tail, false);
|
||
|
if (begin) {
|
||
|
cTextToken *t = new cTextToken();
|
||
|
t->constValue = begin;
|
||
|
textTokens.Add(t);
|
||
|
}
|
||
|
head = tail;
|
||
|
tail++;
|
||
|
while (*tail) {
|
||
|
if (*tail == '|') {
|
||
|
char *token = CopyTextPart(head, tail);
|
||
|
cTextToken *t = new cTextToken();
|
||
|
t->type = eTexttokenType::condstringtoken;
|
||
|
t->constValue = token;
|
||
|
textTokens.Add(t);
|
||
|
head = tail+1;
|
||
|
break;
|
||
|
}
|
||
|
tail++;
|
||
|
}
|
||
|
} else if (*tail == '{') {
|
||
|
char *begin = CopyTextPart(head, tail, false);
|
||
|
if (begin) {
|
||
|
cTextToken *t = new cTextToken();
|
||
|
t->constValue = begin;
|
||
|
textTokens.Add(t);
|
||
|
}
|
||
|
head = tail;
|
||
|
tail++;
|
||
|
while (*tail) {
|
||
|
if (*tail == '}') {
|
||
|
char *token = CopyTextPart(head, tail);
|
||
|
cTextToken *t = new cTextToken();
|
||
|
t->type = eTexttokenType::stringtoken;
|
||
|
t->constValue = token;
|
||
|
textTokens.Add(t);
|
||
|
head = tail+1;
|
||
|
break;
|
||
|
}
|
||
|
tail++;
|
||
|
}
|
||
|
}
|
||
|
tail++;
|
||
|
}
|
||
|
char *end = CopyTextPart(head, tail, false);
|
||
|
if (end) {
|
||
|
cTextToken *t = new cTextToken();
|
||
|
t->constValue = end;
|
||
|
textTokens.Add(t);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void cTextExpr::PrepareTokens(void) {
|
||
|
bool error = false;
|
||
|
for (cTextToken *t = textTokens.First(); t; t = textTokens.Next(t)) {
|
||
|
if (t->type == eTexttokenType::condstringtoken) {
|
||
|
ParseCondToken(t);
|
||
|
continue;
|
||
|
} else if (t->type != eTexttokenType::stringtoken)
|
||
|
continue;
|
||
|
if (ParsePrintfToken(t)) {
|
||
|
continue;
|
||
|
}
|
||
|
if (CheckGlobals(t)) {
|
||
|
continue;
|
||
|
}
|
||
|
int tokenIndex = tokenContainer->IntTokenIndex(t->constValue);
|
||
|
if (tokenIndex >= 0) {
|
||
|
t->tokenIndex = tokenIndex;
|
||
|
t->type = eTexttokenType::inttoken;
|
||
|
continue;
|
||
|
}
|
||
|
tokenIndex = tokenContainer->StringTokenIndex(t->constValue);
|
||
|
if (tokenIndex >= 0) {
|
||
|
t->tokenIndex = tokenIndex;
|
||
|
t->type = eTexttokenType::stringtoken;
|
||
|
continue;
|
||
|
}
|
||
|
tokenIndex = tokenContainer->LoopTokenIndex(t->constValue);
|
||
|
if (tokenIndex >= 0) {
|
||
|
t->tokenIndex = tokenIndex;
|
||
|
t->type = eTexttokenType::looptoken;
|
||
|
continue;
|
||
|
}
|
||
|
esyslog("skindesigner: invalid text token %s in expression \"%s\"", t->constValue, expr);
|
||
|
error = true;
|
||
|
break;
|
||
|
}
|
||
|
if (error) {
|
||
|
textTokens.Clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool cTextExpr::CheckGlobals(cTextToken *t) {
|
||
|
if (!globals || !t->constValue)
|
||
|
return false;
|
||
|
|
||
|
string name = t->constValue;
|
||
|
name = name.substr(1, name.size()-2);
|
||
|
string replacement = "";
|
||
|
if (globals->GetString(name, replacement)) {
|
||
|
free(t->constValue);
|
||
|
t->constValue = strdup(replacement.c_str());
|
||
|
t->type = eTexttokenType::constant;
|
||
|
return true;
|
||
|
}
|
||
|
int numReplacement = 0;
|
||
|
if (globals->GetInt(name, numReplacement)) {
|
||
|
free(t->constValue);
|
||
|
cString repl = cString::sprintf("%d", numReplacement);
|
||
|
t->constValue = strdup(*repl);
|
||
|
t->type = eTexttokenType::constant;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool cTextExpr::ParsePrintfToken(cTextToken *t) {
|
||
|
//check valid printftoken
|
||
|
char *start = strstr(t->constValue, "printf(");
|
||
|
if (!start)
|
||
|
return false;
|
||
|
char *end = strchr(start, ')');
|
||
|
if (!end)
|
||
|
return false;
|
||
|
t->type = eTexttokenType::printftoken;
|
||
|
|
||
|
//find printf expression
|
||
|
char *startExpr = strchr(t->constValue, '\'');
|
||
|
if (!startExpr)
|
||
|
return false;
|
||
|
char *endExpr = strchr(startExpr + 1, '\'');
|
||
|
if (!endExpr)
|
||
|
return false;
|
||
|
int expLen = endExpr - startExpr - 1;
|
||
|
char buffer[100];
|
||
|
strncpy(buffer, startExpr+1, expLen);
|
||
|
buffer[expLen] = '\0';
|
||
|
t->printfExpr = strdup(buffer);
|
||
|
|
||
|
//find variables
|
||
|
char *startVar = strchr(t->constValue, ',');
|
||
|
if (!startVar)
|
||
|
return false;
|
||
|
startVar++;
|
||
|
vector<string> varTokens;
|
||
|
char *nextVar = NULL;
|
||
|
while (nextVar = strchr(startVar, ',')) {
|
||
|
while(isspace(*startVar))
|
||
|
startVar++;
|
||
|
int varLen = nextVar - startVar;
|
||
|
buffer[0] = '{';
|
||
|
strncpy((char*)buffer + 1, startVar, varLen);
|
||
|
buffer[varLen+1] = '}';
|
||
|
buffer[varLen+2] = '\0';
|
||
|
int i = 1;
|
||
|
while(isspace(buffer[varLen-i])) {
|
||
|
buffer[varLen-i] = '}';
|
||
|
buffer[varLen-i+1] = '\0';
|
||
|
i++;
|
||
|
}
|
||
|
varTokens.push_back(buffer);
|
||
|
startVar = nextVar + 1;
|
||
|
}
|
||
|
if (startVar+1) {
|
||
|
int varLen = end - startVar;
|
||
|
buffer[0] = '{';
|
||
|
strncpy((char*)buffer + 1, startVar + 1, varLen);
|
||
|
buffer[varLen] = '}';
|
||
|
buffer[varLen+1] = '\0';
|
||
|
varTokens.push_back(buffer);
|
||
|
}
|
||
|
//evaluate variables
|
||
|
bool ok = true;
|
||
|
for (size_t i=0; i < varTokens.size(); i++) {
|
||
|
sPrintfInfo info;
|
||
|
int tokenIndex = tokenContainer->IntTokenIndex(varTokens[i].c_str());
|
||
|
if (tokenIndex >= 0) {
|
||
|
info.type = ePrintfVarType::inttoken;
|
||
|
info.index = tokenIndex;
|
||
|
t->printfVarIndices.push_back(info);
|
||
|
continue;
|
||
|
}
|
||
|
tokenIndex = tokenContainer->StringTokenIndex(varTokens[i].c_str());
|
||
|
if (tokenIndex >= 0) {
|
||
|
info.type = ePrintfVarType::stringtoken;
|
||
|
info.index = tokenIndex;
|
||
|
t->printfVarIndices.push_back(info);
|
||
|
continue;
|
||
|
}
|
||
|
tokenIndex = tokenContainer->LoopTokenIndex(varTokens[i].c_str());
|
||
|
if (tokenIndex >= 0) {
|
||
|
info.type = ePrintfVarType::looptoken;
|
||
|
info.index = tokenIndex;
|
||
|
t->printfVarIndices.push_back(info);
|
||
|
continue;
|
||
|
}
|
||
|
ok = false;
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
void cTextExpr::DeterminatePrintfToken(cTextToken *t) {
|
||
|
int numVars = t->printfVarIndices.size();
|
||
|
vector<int> results;
|
||
|
for (int i=0; i < numVars; i++) {
|
||
|
if (t->printfVarIndices[i].type == ePrintfVarType::inttoken) {
|
||
|
results.push_back(tokenContainer->IntToken(t->printfVarIndices[i].index));
|
||
|
} else if (t->printfVarIndices[i].type == ePrintfVarType::stringtoken) {
|
||
|
if (tokenContainer->StringToken(t->printfVarIndices[i].index)) {
|
||
|
results.push_back(atoi(tokenContainer->StringToken(t->printfVarIndices[i].index)));
|
||
|
}
|
||
|
} else if (t->printfVarIndices[i].type == ePrintfVarType::looptoken && loopInfo && loopInfo->row >= 0) {
|
||
|
if (tokenContainer->LoopToken(loopInfo->index, loopInfo->row, t->printfVarIndices[i].index)) {
|
||
|
results.push_back(atoi(tokenContainer->LoopToken(loopInfo->index, loopInfo->row, t->printfVarIndices[i].index)));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (numVars) {
|
||
|
case 1:
|
||
|
t->printfResult = strdup(*cString::sprintf(t->printfExpr, results[0]));
|
||
|
break;
|
||
|
case 2:
|
||
|
t->printfResult = strdup(*cString::sprintf(t->printfExpr, results[0], results[1]));
|
||
|
break;
|
||
|
case 3:
|
||
|
t->printfResult = strdup(*cString::sprintf(t->printfExpr, results[0], results[1], results[2]));
|
||
|
break;
|
||
|
case 4:
|
||
|
t->printfResult = strdup(*cString::sprintf(t->printfExpr, results[0], results[1], results[2], results[3]));
|
||
|
break;
|
||
|
case 5:
|
||
|
t->printfResult = strdup(*cString::sprintf(t->printfExpr, results[0], results[1], results[2], results[3], results[4]));
|
||
|
break;
|
||
|
case 6:
|
||
|
t->printfResult = strdup(*cString::sprintf(t->printfExpr, results[0], results[1], results[2], results[3], results[4], results[5]));
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void cTextExpr::ParseCondToken(cTextToken *t) {
|
||
|
char *head = t->constValue;
|
||
|
char *tail = t->constValue;
|
||
|
head++;
|
||
|
tail++;
|
||
|
char *token = NULL;
|
||
|
while (*tail) {
|
||
|
if (*tail == '{') {
|
||
|
t->condStart = CopyTextPart(head, tail, false);
|
||
|
head = tail;
|
||
|
tail++;
|
||
|
while (*tail) {
|
||
|
if (*tail == '}') {
|
||
|
token = CopyTextPart(head, tail);
|
||
|
head = tail+1;
|
||
|
break;
|
||
|
}
|
||
|
tail++;
|
||
|
}
|
||
|
}
|
||
|
tail++;
|
||
|
}
|
||
|
tail--;
|
||
|
t->condEnd = CopyTextPart(head, tail, false);
|
||
|
if (!token) {
|
||
|
esyslog("skindesigner: invalid conditional texttoken %s in expression \"%s\"", t->constValue, expr);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int tokenIndex = tokenContainer->StringTokenIndex(token);
|
||
|
if (tokenIndex >= 0) {
|
||
|
t->tokenIndex = tokenIndex;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
tokenIndex = tokenContainer->IntTokenIndex(token);
|
||
|
if (tokenIndex >= 0) {
|
||
|
t->tokenIndex = tokenIndex;
|
||
|
t->type = eTexttokenType::condinttoken;
|
||
|
return;
|
||
|
}
|
||
|
esyslog("skindesigner: invalid token %s in expression\"%s\"", token, expr);
|
||
|
}
|
||
|
|
||
|
char *cTextExpr::CopyTextPart(char *start, char *stop, bool incLastChar) {
|
||
|
if (!start)
|
||
|
return NULL;
|
||
|
if (start >= stop)
|
||
|
return NULL;
|
||
|
char *val = NULL;
|
||
|
size_t len = 0;
|
||
|
if (stop) {
|
||
|
//defined end
|
||
|
len = stop - start + 1;
|
||
|
} else {
|
||
|
//search end of text
|
||
|
char *p = start;
|
||
|
while (*p)
|
||
|
len++; p++;
|
||
|
len++;
|
||
|
}
|
||
|
val = (char*)malloc(len+1);
|
||
|
memset(val, 0, len+1);
|
||
|
if (!incLastChar)
|
||
|
len--;
|
||
|
memcpy(val, start, len);
|
||
|
return val;
|
||
|
}
|