summaryrefslogtreecommitdiff
path: root/glcdskin/function.c
diff options
context:
space:
mode:
Diffstat (limited to 'glcdskin/function.c')
-rw-r--r--glcdskin/function.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/glcdskin/function.c b/glcdskin/function.c
new file mode 100644
index 0000000..8582ad5
--- /dev/null
+++ b/glcdskin/function.c
@@ -0,0 +1,454 @@
+/*
+ * GraphLCD skin library
+ *
+ * function.c - skin functions class
+ *
+ * This file is released under the GNU General Public License. Refer
+ * to the COPYING file distributed with this package.
+ *
+ * based on text2skin
+ *
+ */
+
+#include <syslog.h>
+
+#include <string.h>
+
+#include "skin.h"
+#include "function.h"
+
+namespace GLCD
+{
+
+static const char * Internals[] =
+{
+ "not", "and", "or", "equal", "gt", "lt", "ge", "le", "ne", "file", "trans",
+ "add", "sub", "mul", "div",
+ "FontTotalWidth",
+ "FontTotalHeight",
+ "FontTotalAscent",
+ "FontSpaceBetween",
+ "FontLineHeight",
+ "FontTextWidth",
+ "FontTextHeight",
+ "ImageWidth",
+ "ImageHeight",
+ NULL
+};
+
+cSkinFunction::cSkinFunction(cSkinObject *Parent)
+: mObject(Parent),
+ mSkin(Parent->Skin()),
+ mType(string),
+ mString(mObject, false),
+ mNumber(0),
+ mNumParams(0)
+{
+}
+
+cSkinFunction::cSkinFunction(const cSkinString & String)
+: mObject(String.Object()),
+ mSkin(String.Skin()),
+ mType(string),
+ mString(String),
+ mNumber(0),
+ mNumParams(0)
+{
+}
+
+cSkinFunction::cSkinFunction(const cSkinFunction & Src)
+: mObject(Src.mObject),
+ mSkin(Src.mSkin),
+ mType(Src.mType),
+ mString(Src.mString),
+ mNumber(Src.mNumber),
+ mNumParams(Src.mNumParams)
+{
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ mParams[i] = new cSkinFunction(*Src.mParams[i]);
+}
+
+cSkinFunction::~cSkinFunction()
+{
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ delete mParams[i];
+}
+
+bool cSkinFunction::Parse(const std::string & Text)
+{
+ const char *text = Text.c_str();
+ const char *ptr = text, *last = text;
+ eType type = undefined_function;
+ int inExpr = 0;
+ cSkinFunction *expr;
+
+ if (*ptr == '\'' || *ptr == '{')
+ {
+ // must be string
+ if (strlen(ptr) < 2
+ || (*ptr == '\'' && *(ptr + strlen(ptr) - 1) != '\'')
+ || (*ptr == '{' && *(ptr + strlen(ptr) - 1) != '}'))
+ {
+ syslog(LOG_ERR, "ERROR: Unmatched string end\n");
+ return false;
+ }
+
+ std::string temp;
+ if (*ptr == '\'')
+ temp.assign(ptr + 1, strlen(ptr) - 2);
+ else
+ temp.assign(ptr);
+
+ int pos = -1;
+ while ((pos = temp.find("\\'", pos + 1)) != -1)
+ temp.replace(pos, 2, "'");
+
+ if (!mString.Parse(temp))
+ return false;
+
+ mType = string;
+ }
+ if (*ptr == '#')
+ {
+ // must be a variable id
+ if (strlen(ptr) < 2)
+ {
+ syslog(LOG_ERR, "ERROR: No variable id given\n");
+ return false;
+ }
+
+ mVariableId.assign(ptr + 1);
+ mType = variable;
+ }
+ else if ((*ptr >= '0' && *ptr <= '9') || *ptr == '-' || *ptr == '+')
+ {
+ // must be number
+ char *end;
+ int num = strtol(ptr, &end, 10);
+ if (end == ptr || *end != '\0')
+ {
+ syslog(LOG_ERR, "ERROR: Invalid numeric value\n");
+ return false;
+ }
+
+ mNumber = num;
+ mType = number;
+ }
+ else
+ {
+ // expression
+ for (; *ptr; ++ptr)
+ {
+ if (*ptr == '(')
+ {
+ if (inExpr++ == 0)
+ {
+ int i;
+ for (i = 0; Internals[i] != NULL; ++i)
+ {
+ if ((size_t)(ptr - last) == strlen(Internals[i])
+ && memcmp(last, Internals[i], ptr - last) == 0)
+ {
+ type = (eType)(INTERNAL + i);
+ break;
+ }
+ }
+
+ if (Internals[i] == NULL)
+ {
+ syslog(LOG_ERR, "ERROR: Unknown function %.*s", (int)(ptr - last), last);
+ return false;
+ }
+ last = ptr + 1;
+ }
+ }
+ else if (*ptr == ',' || *ptr == ')')
+ {
+ if (inExpr == 0)
+ {
+ syslog(LOG_ERR, "ERROR: Unmatched '%c' in expression", *ptr);
+ return false;
+ }
+
+ if (inExpr == 1)
+ {
+ expr = new cSkinFunction(mObject);
+ if (!expr->Parse(std::string(last, ptr - last)))
+ {
+ delete expr;
+ return false;
+ }
+
+ if (mNumParams == MAXPARAMETERS)
+ {
+ syslog(LOG_ERR, "ERROR: Too many parameters to function, maximum is %d",
+ MAXPARAMETERS);
+ return false;
+ }
+
+ mType = type;
+ mParams[mNumParams++] = expr;
+ last = ptr + 1;
+ }
+
+ if (*ptr == ')')
+ {
+ if (inExpr == 1)
+ {
+ int params = 0;
+
+ switch (mType)
+ {
+ case fun_and:
+ case fun_or:
+ params = -1;
+ break;
+
+ case fun_eq:
+ case fun_ne:
+ case fun_gt:
+ case fun_lt:
+ case fun_ge:
+ case fun_le:
+ params = 2;
+ break;
+
+ case fun_not:
+ case fun_trans:
+ case fun_file:
+ params = 1;
+ break;
+
+ case funAdd:
+ case funSub:
+ case funMul:
+ params = -1;
+ break;
+
+ case funDiv:
+ params = 2;
+ break;
+
+ case funFontTotalWidth:
+ case funFontTotalHeight:
+ case funFontTotalAscent:
+ case funFontSpaceBetween:
+ case funFontLineHeight:
+ params = 1;
+ break;
+
+ case funFontTextWidth:
+ case funFontTextHeight:
+ params = 2;
+ break;
+
+ case funImageWidth:
+ case funImageHeight:
+ params = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (params != -1 && mNumParams != (uint32_t) params)
+ {
+ syslog(LOG_ERR, "ERROR: Text2Skin: Wrong number of parameters to %s, "
+ "expecting %d", Internals[mType - INTERNAL], params);
+ return false;
+ }
+ }
+
+ --inExpr;
+ }
+ }
+ }
+
+ if (inExpr > 0)
+ {
+ syslog(LOG_ERR, "ERROR: Expecting ')' in expression");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+cType cSkinFunction::FunFile(const cType & Param) const
+{
+ cImageCache * cache = mSkin->ImageCache();
+ GLCD::cImage * image = cache->Get(Param);
+ return image ? (cType) Param : (cType) false;
+}
+
+cType cSkinFunction::FunFont(eType Function, const cType &Param1, const cType &Param2) const
+{
+ cSkinFont * skinFont = mSkin->GetFont(Param1);
+ if (!skinFont)
+ return false;
+
+ const cFont * font = skinFont->Font();
+ if (!font)
+ return false;
+ switch (Function)
+ {
+ case funFontTotalWidth:
+ return font->TotalWidth();
+ case funFontTotalHeight:
+ return font->TotalHeight();
+ case funFontTotalAscent:
+ return font->TotalAscent();
+ case funFontSpaceBetween:
+ return font->SpaceBetween();
+ case funFontLineHeight:
+ return font->LineHeight();
+ case funFontTextWidth:
+ return font->Width((const std::string) Param2);
+ case funFontTextHeight:
+ return font->Height((const std::string) Param2);
+ default:
+ break;
+ }
+ return false;
+}
+
+cType cSkinFunction::FunImage(eType Function, const cType &Param) const
+{
+ cImageCache * cache = mSkin->ImageCache();
+ GLCD::cImage * image = cache->Get(Param);
+
+ if (!image)
+ return false;
+
+ switch (Function)
+ {
+ case funImageWidth:
+ return (int) image->Width();
+ case funImageHeight:
+ return (int) image->Height();
+ default:
+ break;
+ }
+ return false;
+}
+
+cType cSkinFunction::Evaluate(void) const
+{
+ switch (mType)
+ {
+ case string:
+ return mString.Evaluate();
+
+ case number:
+ return mNumber;
+
+ case variable:
+ {
+ cSkinVariable * variable = mSkin->GetVariable(mVariableId);
+ if (variable)
+ return variable->Value();
+ return false;
+ }
+
+ case fun_not:
+ return !mParams[0]->Evaluate();
+
+ case fun_and:
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ {
+ if (!mParams[i]->Evaluate())
+ return false;
+ }
+ return true;
+
+ case fun_or:
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ {
+ if (mParams[i]->Evaluate())
+ return true;
+ }
+ return false;
+
+ case fun_eq:
+ return mParams[0]->Evaluate() == mParams[1]->Evaluate();
+
+ case fun_ne:
+ return mParams[0]->Evaluate() != mParams[1]->Evaluate();
+
+ case fun_gt:
+ return mParams[0]->Evaluate() > mParams[1]->Evaluate();
+
+ case fun_lt:
+ return mParams[0]->Evaluate() < mParams[1]->Evaluate();
+
+ case fun_ge:
+ return mParams[0]->Evaluate() >= mParams[1]->Evaluate();
+
+ case fun_le:
+ return mParams[0]->Evaluate() <= mParams[1]->Evaluate();
+
+ case fun_file:
+ return FunFile(mParams[0]->Evaluate());
+
+ case fun_trans:
+ return mSkin->Config().Translate(mParams[0]->Evaluate());
+
+ case funAdd:
+ {
+ int result = 0;
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ {
+ result += (int) mParams[i]->Evaluate();
+ }
+ return result;
+ }
+
+ case funSub:
+ if (mNumParams > 0)
+ {
+ int result = (int) mParams[0]->Evaluate();
+ for (uint32_t i = 1; i < mNumParams; ++i)
+ {
+ result -= (int) mParams[i]->Evaluate();
+ }
+ return result;
+ }
+ return 0;
+
+ case funMul:
+ {
+ int result = 1;
+ for (uint32_t i = 0; i < mNumParams; ++i)
+ {
+ result *= (int) mParams[i]->Evaluate();
+ }
+ return result;
+ }
+
+ case funDiv:
+ return ((int) mParams[0]->Evaluate() / (int) mParams[1]->Evaluate());
+
+ case funFontTotalWidth:
+ case funFontTotalHeight:
+ case funFontTotalAscent:
+ case funFontSpaceBetween:
+ case funFontLineHeight:
+ return FunFont(mType, mParams[0]->Evaluate(), "");
+
+ case funFontTextWidth:
+ case funFontTextHeight:
+ return FunFont(mType, mParams[0]->Evaluate(), mParams[1]->Evaluate());
+
+ case funImageWidth:
+ case funImageHeight:
+ return FunImage(mType, mParams[0]->Evaluate());
+
+ default:
+ //Dprintf("unknown function code\n");
+ syslog(LOG_ERR, "ERROR: Unknown function code called (this shouldn't happen)");
+ break;
+ }
+ return false;
+}
+
+} // end of namespace