/* Copyright (C) 2004-2007 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include "uservars.h" #include "epgsearchcats.h" #include "epgsearchtools.h" #include "log.h" cUserVars UserVars; string cPlugconfdirVar::dir = ""; // cUserVar cUserVar::cUserVar() { oldEvent = NULL; } string cUserVar::Evaluate(const cEvent* e, bool escapeStrings) { if (oldEvent && oldEvent == e && oldescapeStrings == escapeStrings) return oldResult; usedVars.clear(); string result; if (IsShellCmd()) result = EvaluateShellCmd(e); else if (IsCondExpr()) result = EvaluateCondExpr(e); else result = EvaluateCompExpr(e); oldResult = result; oldEvent = e; oldescapeStrings = escapeStrings; // avoid double dir separators int pos = 0; while((pos = result.find("~~")) >= 0) result.replace(pos, 2, "~"); return result; } string cUserVar::EvaluateShellCmd(const cEvent* e) { if (!varparser.cmd) return ""; string cmdArgs; if (varparser.cmdArgs != "") { string args = varparser.cmdArgs; varparser.compExpr = args; //handle the args as composed expr cmdArgs = EvaluateCompExpr(e, true); } const char* res = varparser.cmd->Execute(cmdArgs.c_str()); string result = res?res:""; int crPos = 0; // remove any CR while((crPos = result.find("\n")) >= 0) result.replace(crPos, 1, ""); return result; } string cUserVar::EvaluateCondExpr(const cEvent* e, bool escapeStrings) { string condresult = ""; cVarExpr leftExp(varparser.condEqLeft); string resLeft = leftExp.Evaluate(e); cVarExpr rightExp(varparser.condEqRight); string resRight = rightExp.Evaluate(e); if (varparser.condOp == condEq && resLeft == resRight) condresult = "1"; // assign any value if (varparser.condOp == condNeq && resLeft != resRight) condresult = "1"; // assign any value cUserVar* condVarTrue = UserVars.GetFromName(varparser.condvarTrue); cUserVar* condVarFalse = UserVars.GetFromName(varparser.condvarFalse); if (!condVarTrue || !condVarFalse) return ""; if (!AddDepVar(condVarTrue)) return ""; if (!AddDepVar(condVarFalse)) return ""; if (condresult != "") { LogFile.Log(3, "using case 'true'"); return condVarTrue->Evaluate(e, escapeStrings); } else { LogFile.Log(3, "using case 'false'"); return condVarFalse->Evaluate(e, escapeStrings); } } string cUserVar::EvaluateCompExpr(const cEvent* e, bool escapeStrings) { string expr = varparser.compExpr; if (expr.find('%') == string::npos) return expr; // handle internal vars like title and subtitle expr = EvaluateInternalVars(expr, e, escapeStrings); // replace ext. EPG variables expr = EvaluateExtEPGVars(expr, e, escapeStrings); // replace other user vars expr = EvaluateUserVars(expr, e, escapeStrings); return expr; } string cUserVar::EvaluateInternalVars(const string& Expr, const cEvent* e, bool escapeStrings) { string expr = Expr; if (expr.find('%') == string::npos) return expr; std::map::iterator it; for (it = UserVars.internalVars.begin(); it != UserVars.internalVars.end(); it++) { string varName = (it->second)->Name(); int varPos = 0; while((varPos = FindIgnoreCase(expr, varName)) >= 0) { usedVars.insert(it->second); expr.replace(varPos, varName.size(), (it->second)->Evaluate(e, escapeStrings)); } } return expr; } string cUserVar::EvaluateExtEPGVars(const string& Expr, const cEvent* e, bool escapeStrings) { string expr = Expr; if (expr.find('%') == string::npos) return expr; std::map::iterator evar; for (evar = UserVars.extEPGVars.begin(); evar != UserVars.extEPGVars.end(); evar++) { string varName = evar->second->Name(); int varPos = 0; while((varPos = FindIgnoreCase(expr, varName)) >= 0) { expr.replace(varPos, varName.size(), evar->second->Evaluate(e, escapeStrings)); usedVars.insert(evar->second); } } return expr; } string cUserVar::EvaluateUserVars(const string& Expr, const cEvent* e, bool escapeStrings) { string expr = Expr; if (expr.find('%') == string::npos) return expr; std::set::iterator it; for (it = UserVars.userVars.begin(); it != UserVars.userVars.end(); it++) { string varName = (*it)->Name(); int varPos = 0; while((varPos = FindIgnoreCase(expr, varName)) >= 0) { if (!AddDepVar(*it)) return ""; expr.replace(varPos, varName.size(), (*it)->Evaluate(e, escapeStrings)); } } return expr; } string cUserVar::EvaluateInternalTimerVars(const string& Expr, const cTimer* t) { string expr = Expr; if (expr.find('%') == string::npos) return expr; std::map::iterator tvar; for (tvar = UserVars.internalTimerVars.begin(); tvar != UserVars.internalTimerVars.end(); tvar++) { string varName = tvar->second->Name(); int varPos = 0; while((varPos = FindIgnoreCase(expr, varName)) >= 0) { expr.replace(varPos, varName.size(), tvar->second->Evaluate(t)); } } return expr; } string cUserVar::EvaluateInternalSearchVars(const string& Expr, const cSearchExt* s) { string expr = Expr; if (expr.find('%') == string::npos) return expr; std::map::iterator svar; for (svar = UserVars.internalSearchVars.begin(); svar != UserVars.internalSearchVars.end(); svar++) { string varName = svar->second->Name(); int varPos = 0; while((varPos = FindIgnoreCase(expr, varName)) >= 0) { expr.replace(varPos, varName.size(), svar->second->Evaluate(s)); } } return expr; } bool cUserVar::DependsOnVar(const string& varName) { string VarName = Strip(varName); cUserVar* var = UserVars.GetFromName(VarName); if (!var) return false; return DependsOnVar(var); } bool cUserVar::DependsOnVar(cUserVar* var) { if (!var) return false; if (usedVars.find(var) != usedVars.end()) return true; std::set::iterator it; for (it = usedVars.begin(); it != usedVars.end(); it++) if ((*it)->DependsOnVar(var)) return true; return false; } bool cUserVar::AddDepVar(cUserVar* var) { if (var == this || var->DependsOnVar(this)) { LogFile.eSysLog("ERROR - found cylic reference to var '%s' in var '%s'", var->Name().c_str(), Name().c_str()); return false; } usedVars.insert(var); return true; } void cUserVar::ResetCache() { oldEvent = NULL; oldResult = ""; } // cUserVarLine bool cUserVarLine::Parse(char *s) { if (s && s[0] == '#') return true; char *p = strchr(s, '='); if (p) { cUserVar* userVar = new cUserVar; if (userVar->varparser.Parse(s)) { UserVars.userVars.insert(userVar); return true; } } return false; } // cUserVars cUserVar* cUserVars::GetFromName(const string& varName) { string VarName = Strip(varName); std::transform(VarName.begin(), VarName.end(), VarName.begin(), tolower); std::map::iterator ivar = internalVars.find(VarName); if (ivar != internalVars.end()) return ivar->second; std::set::iterator uvar; for (uvar = userVars.begin(); uvar != userVars.end(); uvar++) if (EqualsNoCase((*uvar)->Name(), VarName)) return (*uvar); std::map::iterator evar = extEPGVars.find(VarName); if (evar != extEPGVars.end()) return evar->second; LogFile.eSysLog("var '%s' not defined!", VarName.c_str()); return NULL; } // cVarExpr string cVarExpr::Evaluate(const cEvent* e) { // create a dummy user var cUserVar var; if (!var.varparser.ParseExp(expr)) return ""; LogFile.Log(3, "start evaluating expression '%s'", expr.c_str()); string result = var.Evaluate(e); LogFile.Log(3, "stop evaluating expression '%s' - result: '%s'", expr.c_str(), result.c_str()); usedVars = var.usedVars; return result; } string cVarExpr::Evaluate(const cTimer* t) { // create a dummy user var cUserVar var; if (!var.varparser.ParseExp(expr)) return ""; usedVars = var.usedVars; return var.EvaluateInternalTimerVars(expr, t); } string cVarExpr::Evaluate(const cSearchExt* s) { // create a dummy user var cUserVar var; if (!var.varparser.ParseExp(expr)) return ""; usedVars = var.usedVars; return var.EvaluateInternalSearchVars(expr, s); } bool cVarExpr::DependsOnVar(const string& varName, const cEvent* e) { string VarName = Strip(varName); if (FindIgnoreCase(expr, VarName) >= 0) return true; // create a dummy user var cUserVar var; var.varparser.varName = expr; if (!var.varparser.ParseExp(expr)) return false; var.Evaluate(e); return var.DependsOnVar(VarName); }