mirror of
https://projects.vdr-developer.org/git/vdr-plugin-skindesigner.git
synced 2023-10-19 17:58:31 +02:00
402 lines
12 KiB
C
402 lines
12 KiB
C
#include "../config.h"
|
|
#include "parameter.h"
|
|
|
|
using namespace std;
|
|
|
|
// --- cNumericParameter -------------------------------------------------------------
|
|
|
|
cNumericParameter::cNumericParameter(string value) {
|
|
this->value = value;
|
|
globals = NULL;
|
|
isValid = false;
|
|
width = 0;
|
|
height = 0;
|
|
columnWidth = -1;
|
|
rowHeight = -1;
|
|
hor = true;
|
|
defaultValue = 0;
|
|
}
|
|
|
|
cNumericParameter::~cNumericParameter(void) {
|
|
}
|
|
|
|
void cNumericParameter::SetAreaSize(int w, int h) {
|
|
width = w;
|
|
height = h;
|
|
}
|
|
|
|
int cNumericParameter::Parse(string &parsedValue) {
|
|
int retVal = defaultValue;
|
|
|
|
if (IsNumber(value)) {
|
|
isValid = true;
|
|
retVal = atoi(value.c_str());
|
|
return retVal;
|
|
}
|
|
|
|
//checking for percent value
|
|
bool isPercentValue = CheckPercentValue(retVal);
|
|
if (isPercentValue) {
|
|
isValid = true;
|
|
return retVal;
|
|
}
|
|
|
|
//checking for expression
|
|
bool isValidExpression = CheckExpression(retVal, parsedValue);
|
|
if (isValidExpression) {
|
|
isValid = true;
|
|
return retVal;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool cNumericParameter::IsNumber(const string& s) {
|
|
string::const_iterator it = s.begin();
|
|
while (it != s.end() && isdigit(*it)) ++it;
|
|
return !s.empty() && it == s.end();
|
|
}
|
|
|
|
bool cNumericParameter::CheckPercentValue(int &val) {
|
|
bool ok = false;
|
|
size_t posPercent = value.find('%');
|
|
if (posPercent != string::npos) {
|
|
string strPerc = value.substr(0, posPercent);
|
|
if (!IsNumber(strPerc)) {
|
|
return ok;
|
|
}
|
|
int perc = atoi(strPerc.c_str());
|
|
if (hor) {
|
|
val = width * perc / 100;
|
|
} else {
|
|
val = height * perc / 100;
|
|
}
|
|
ok = true;
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool cNumericParameter::CheckExpression(int &val, string &parsedVal) {
|
|
bool ok = false;
|
|
string parsedValue = value;
|
|
//remove white spaces
|
|
parsedValue.erase( std::remove_if( parsedValue.begin(), parsedValue.end(), ::isspace ), parsedValue.end() );
|
|
|
|
//check and replace {areawidth} and {areaheight} tokens
|
|
string tokenWidth = "{areawidth}";
|
|
string tokenHeight = "{areaheight}";
|
|
|
|
stringstream sw;
|
|
sw << width;
|
|
string strWidth = sw.str();
|
|
stringstream sh;
|
|
sh << height;
|
|
string strHeight = sh.str();
|
|
|
|
bool foundToken = true;
|
|
while(foundToken) {
|
|
size_t foundTokenWidth = parsedValue.find(tokenWidth);
|
|
if (foundTokenWidth != string::npos) {
|
|
parsedValue = parsedValue.replace(foundTokenWidth, tokenWidth.size(), strWidth);
|
|
} else {
|
|
foundToken = false;
|
|
}
|
|
}
|
|
|
|
foundToken = true;
|
|
while(foundToken) {
|
|
size_t foundTokenHeight = parsedValue.find(tokenHeight);
|
|
if (foundTokenHeight != string::npos) {
|
|
parsedValue = parsedValue.replace(foundTokenHeight, tokenHeight.size(), strHeight);
|
|
} else {
|
|
foundToken = false;
|
|
}
|
|
}
|
|
|
|
//check and replace {columnwidth} and {rowheight} tokens for loop functions
|
|
if (columnWidth > 0 || rowHeight > 0) {
|
|
tokenWidth = "{columnwidth}";
|
|
tokenHeight = "{rowheight}";
|
|
stringstream cw;
|
|
cw << columnWidth;
|
|
strWidth = cw.str();
|
|
stringstream rh;
|
|
rh << rowHeight;
|
|
strHeight = rh.str();
|
|
|
|
foundToken = true;
|
|
while(foundToken) {
|
|
size_t foundTokenWidth = parsedValue.find(tokenWidth);
|
|
if (foundTokenWidth != string::npos) {
|
|
parsedValue = parsedValue.replace(foundTokenWidth, tokenWidth.size(), strWidth);
|
|
} else {
|
|
foundToken = false;
|
|
}
|
|
}
|
|
|
|
foundToken = true;
|
|
while(foundToken) {
|
|
size_t foundTokenHeight = parsedValue.find(tokenHeight);
|
|
if (foundTokenHeight != string::npos) {
|
|
parsedValue = parsedValue.replace(foundTokenHeight, tokenHeight.size(), strHeight);
|
|
} else {
|
|
foundToken = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (globals) {
|
|
globals->ReplaceIntVars(parsedValue);
|
|
globals->ReplaceDoubleVars(parsedValue);
|
|
}
|
|
|
|
if (IsNumber(parsedValue)) {
|
|
ok = true;
|
|
val = atoi(parsedValue.c_str());
|
|
return ok;
|
|
}
|
|
|
|
if (!ValidNumericExpression(parsedValue)) {
|
|
parsedVal = parsedValue;
|
|
return ok;
|
|
}
|
|
ok = true;
|
|
char * expression = new char[parsedValue.size() + 1];
|
|
std::copy(parsedValue.begin(), parsedValue.end(), expression);
|
|
expression[parsedValue.size()] = '\0';
|
|
int expRes = EvaluateTheExpression(expression);
|
|
val = expRes;
|
|
delete[] expression;
|
|
return ok;
|
|
}
|
|
|
|
bool cNumericParameter::ValidNumericExpression(string &parsedValue) {
|
|
string::const_iterator it = parsedValue.begin();
|
|
while (it != parsedValue.end() && (isdigit(*it) || *it == '.' || *it == ',' || *it == '+' || *it == '-' || *it == '*' || *it == '/')) ++it;
|
|
return !parsedValue.empty() && it == parsedValue.end();
|
|
}
|
|
|
|
int cNumericParameter::EvaluateTheExpression(char* expr) {
|
|
return round(ParseSummands(expr));
|
|
}
|
|
|
|
double cNumericParameter::ParseAtom(char*& expr) {
|
|
// Read the number from string
|
|
char* end_ptr;
|
|
double res = strtod(expr, &end_ptr);
|
|
// Advance the pointer and return the result
|
|
expr = end_ptr;
|
|
return res;
|
|
}
|
|
|
|
// Parse multiplication and division
|
|
double cNumericParameter::ParseFactors(char*& expr) {
|
|
double num1 = ParseAtom(expr);
|
|
for(;;) {
|
|
// Save the operation
|
|
char op = *expr;
|
|
if(op != '/' && op != '*')
|
|
return num1;
|
|
expr++;
|
|
double num2 = ParseAtom(expr);
|
|
// Perform the saved operation
|
|
if(op == '/') {
|
|
if (num2 != 0) {
|
|
num1 /= num2;
|
|
}
|
|
} else
|
|
num1 *= num2;
|
|
}
|
|
}
|
|
|
|
// Parse addition and subtraction
|
|
double cNumericParameter::ParseSummands(char*& expr) {
|
|
double num1 = ParseFactors(expr);
|
|
for(;;) {
|
|
char op = *expr;
|
|
if(op != '-' && op != '+')
|
|
return num1;
|
|
expr++;
|
|
double num2 = ParseFactors(expr);
|
|
if(op == '-')
|
|
num1 -= num2;
|
|
else
|
|
num1 += num2;
|
|
}
|
|
}
|
|
|
|
// --- cConditionalParameter -------------------------------------------------------------
|
|
|
|
cConditionalParameter::cConditionalParameter(cGlobals *globals, string value) {
|
|
this->globals = globals;
|
|
isTrue = false;
|
|
this->value = value;
|
|
type = cpNone;
|
|
}
|
|
|
|
cConditionalParameter::~cConditionalParameter(void) {
|
|
}
|
|
|
|
void cConditionalParameter::Tokenize(void) {
|
|
size_t posAnd = value.find("++");
|
|
if (posAnd != string::npos) {
|
|
type = cpAnd;
|
|
TokenizeValue("++");
|
|
} else {
|
|
size_t posOr = value.find("||");
|
|
if (posOr != string::npos) {
|
|
type = cpOr;
|
|
TokenizeValue("||");
|
|
}
|
|
}
|
|
if (type == cpNone) {
|
|
InsertCondition(value);
|
|
}
|
|
}
|
|
|
|
void cConditionalParameter::Evaluate(map < string, int > *intTokens, map < string, string > *stringTokens) {
|
|
isTrue = false;
|
|
bool first = true;
|
|
for (vector<sCondition>::iterator cond = conditions.begin(); cond != conditions.end(); cond++) {
|
|
bool tokenTrue = false;
|
|
|
|
if (cond->type == ctStringSet) {
|
|
if (stringTokens) {
|
|
map < string, string >::iterator hit = stringTokens->find(cond->tokenName);
|
|
if (hit != stringTokens->end()) {
|
|
string value = hit->second;
|
|
if (value.size() > 0)
|
|
tokenTrue = true;
|
|
}
|
|
}
|
|
} else if (cond->type == ctStringEmpty) {
|
|
if (stringTokens) {
|
|
map < string, string >::iterator hit = stringTokens->find(cond->tokenName);
|
|
if (hit != stringTokens->end()) {
|
|
string value = hit->second;
|
|
if (value.size() == 0)
|
|
tokenTrue = true;
|
|
} else {
|
|
tokenTrue = true;
|
|
}
|
|
} else {
|
|
tokenTrue = true;
|
|
}
|
|
} else {
|
|
int tokenValue = EvaluateParameter(cond->tokenName, intTokens, stringTokens);
|
|
if (cond->type == ctBool) {
|
|
tokenTrue = tokenValue;
|
|
} else if (cond->type == ctGreater) {
|
|
tokenTrue = (tokenValue > cond->compareValue) ? true : false;
|
|
} else if (cond->type == ctLower) {
|
|
tokenTrue = (tokenValue < cond->compareValue) ? true : false;
|
|
} else if (cond->type == ctEquals) {
|
|
tokenTrue = (tokenValue == cond->compareValue) ? true : false;
|
|
}
|
|
}
|
|
|
|
if (cond->isNegated)
|
|
tokenTrue = !tokenTrue;
|
|
if (type == cpAnd) {
|
|
if (first)
|
|
isTrue = tokenTrue;
|
|
else
|
|
isTrue = isTrue && tokenTrue;
|
|
} else if (type == cpOr) {
|
|
isTrue = isTrue || tokenTrue;
|
|
} else {
|
|
isTrue = tokenTrue;
|
|
}
|
|
first = false;
|
|
}
|
|
}
|
|
|
|
int cConditionalParameter::EvaluateParameter(string token, map < string, int > *intTokens, map < string, string > *stringTokens) {
|
|
//first check globals
|
|
int result = 0;
|
|
if (globals->GetInt(token, result))
|
|
return result;
|
|
//then check custom tokens
|
|
if (globals->GetCustomInt(token, result))
|
|
return result;
|
|
//then check tokens
|
|
if (intTokens) {
|
|
map < string, int >::iterator hit = intTokens->find(token);
|
|
if (hit != intTokens->end()) {
|
|
return hit->second;
|
|
}
|
|
}
|
|
if (stringTokens) {
|
|
map < string, string >::iterator hit = stringTokens->find(token);
|
|
if (hit != stringTokens->end()) {
|
|
string value = hit->second;
|
|
return atoi(value.c_str());
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void cConditionalParameter::TokenizeValue(string sep) {
|
|
string buffer = value;
|
|
bool sepFound = true;
|
|
while (sepFound) {
|
|
size_t posSep = buffer.find(sep);
|
|
if (posSep == string::npos) {
|
|
InsertCondition(buffer);
|
|
sepFound = false;
|
|
}
|
|
string token = buffer.substr(0, posSep);
|
|
buffer = buffer.replace(0, posSep + sep.size(), "");
|
|
InsertCondition(token);
|
|
}
|
|
}
|
|
|
|
void cConditionalParameter::InsertCondition(string cond) {
|
|
cond.erase( std::remove_if( cond.begin(), cond.end(), ::isspace ), cond.end() );
|
|
|
|
if (cond.size() < 1)
|
|
return;
|
|
|
|
size_t tokenStart = cond.find('{');
|
|
size_t tokenEnd = cond.find('}');
|
|
|
|
if (tokenStart == string::npos || tokenEnd == string::npos || tokenStart > tokenEnd)
|
|
return;
|
|
|
|
string tokenName = cond.substr(tokenStart + 1, tokenEnd - tokenStart - 1);
|
|
string rest = cond.replace(tokenStart, tokenEnd - tokenStart + 1, "");
|
|
|
|
sCondition sCond;
|
|
sCond.tokenName = tokenName;
|
|
sCond.type = ctBool;
|
|
sCond.compareValue = 0;
|
|
sCond.isNegated = false;
|
|
if (!rest.compare("not")) {
|
|
sCond.isNegated = true;
|
|
} else if (!rest.compare("isset")) {
|
|
sCond.type = ctStringSet;
|
|
} else if (!rest.compare("empty")) {
|
|
sCond.type = ctStringEmpty;
|
|
} else if (startswith(rest.c_str(), "gt(")) {
|
|
string compVal = rest.substr(4, rest.size() - 5);
|
|
sCond.compareValue = atoi(compVal.c_str());
|
|
sCond.type = ctGreater;
|
|
} else if (startswith(rest.c_str(), "lt(")) {
|
|
string compVal = rest.substr(4, rest.size() - 5);
|
|
sCond.compareValue = atoi(compVal.c_str());
|
|
sCond.type = ctLower;
|
|
} else if (startswith(rest.c_str(), "eq(")) {
|
|
string compVal = rest.substr(4, rest.size() - 5);
|
|
sCond.compareValue = atoi(compVal.c_str());
|
|
sCond.type = ctEquals;
|
|
}
|
|
|
|
conditions.push_back(sCond);
|
|
}
|
|
|
|
void cConditionalParameter::Debug(void) {
|
|
dsyslog("skindesigner: Condition %s, Type: %s, cond is %s", value.c_str(), (type == cpAnd)?"and combination":((type == cpOr)?"or combination":"single param") , isTrue?"true":"false");
|
|
for (vector<sCondition>::iterator it = conditions.begin(); it != conditions.end(); it++) {
|
|
dsyslog("skindesigner: cond token %s, type: %d, compareValue %d, negated: %d", it->tokenName.c_str(), it->type, it->compareValue, it->isNegated);
|
|
}
|
|
} |