diff options
Diffstat (limited to 'glcdskin/parser.c')
-rw-r--r-- | glcdskin/parser.c | 185 |
1 files changed, 131 insertions, 54 deletions
diff --git a/glcdskin/parser.c b/glcdskin/parser.c index b137a5f..31b3106 100644 --- a/glcdskin/parser.c +++ b/glcdskin/parser.c @@ -24,20 +24,20 @@ namespace GLCD { #define TAG_ERR_REMAIN(_context) do { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected tag %s within %s", \ - name.c_str(), _context); \ + errorDetail = "Unexpected tag "+name+" within "+ _context; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } while (0) #define TAG_ERR_CHILD(_context) do { \ - syslog(LOG_ERR, "ERROR: Text2Skin: No child tag %s expected within %s", \ - name.c_str(), _context); \ + errorDetail = "No child tag "+name+" expected within "+ _context; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } while (0) #define TAG_ERR_END(_context) do { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected closing tag for %s within %s", \ - name.c_str(), _context); \ + errorDetail = "Unexpected closing tag for "+name+" within "+ _context; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } while (0) @@ -49,8 +49,8 @@ namespace GLCD #define ATTRIB_MAN_STRING(_attr,_target) \ ATTRIB_OPT_STRING(_attr,_target) \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+ name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } @@ -59,8 +59,8 @@ namespace GLCD char *_e; const char *_t = attrs[_attr].c_str(); \ long _l = strtol(_t, &_e, 10); \ if (_e ==_t || *_e != '\0') { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Invalid numeric value \"%s\" in attribute %s", \ - _t, _attr); \ + errorDetail = "Invalid numeric value \""+ (std::string)_t +"\" in attribute "+ (std::string)_attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } else \ _target = _l; \ @@ -69,8 +69,8 @@ namespace GLCD #define ATTRIB_MAN_NUMBER(_attr,_target) \ ATTRIB_OPT_NUMBER(_attr,_target) \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } @@ -81,8 +81,8 @@ namespace GLCD else if (attrs[_attr] == "no") \ _target = false; \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Invalid boolean value \"%s\" in attribute %s", \ - attrs[_attr].c_str(), _attr); \ + errorDetail = "Invalid boolean value \""+ attrs[_attr] +"\" in attribute "+ _attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } \ } @@ -90,16 +90,16 @@ namespace GLCD #define ATTRIB_MAN_BOOL(_attr,_target) \ ATTRIB_OPT_BOOL(_attr,_target) \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } #define ATTRIB_OPT_FUNC(_attr,_func) \ if (attrs.find(_attr) != attrs.end()) { \ if (!_func(attrs[_attr])) { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected value %s for attribute %s", \ - attrs[_attr].c_str(), _attr); \ + errorDetail = "Unexpected value \""+ attrs[_attr] +"\" for attribute "+ (std::string)_attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } \ } @@ -107,16 +107,16 @@ namespace GLCD #define ATTRIB_MAN_FUNC(_attr,_func) \ ATTRIB_OPT_FUNC(_attr,_func) \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } #define ATTRIB_OPT_FUNC_PARAM(_attr,_func,_param) \ if (attrs.find(_attr) != attrs.end()) { \ if (!_func(attrs[_attr],_param)) { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected value %s for attribute %s", \ - attrs[_attr].c_str(), _attr); \ + errorDetail = "Unexpected value "+ attrs[_attr] +" for attribute "+ (std::string)_attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } \ } @@ -124,8 +124,8 @@ namespace GLCD #define ATTRIB_MAN_FUNC_PARAM(_attr,_func,_param) \ ATTRIB_OPT_FUNC_PARAM(_attr,_func,_param) \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } @@ -133,31 +133,93 @@ static std::vector<std::string> context; static cSkin * skin = NULL; static cSkinFont * font = NULL; static cSkinVariable * variable = NULL; +static cSkinVariable * variable_default = NULL; static cSkinDisplay * display = NULL; static std::vector <cSkinObject *> parents; static cSkinObject * object = NULL; static uint32_t oindex = 0; +static std::string errorDetail = ""; +static std::string condblock_cond = ""; + + +static bool CheckSkinVersion(const std::string & version) { + float currv; + char* ecptr = NULL; + const char* verscstr = version.c_str(); + currv = strtof(verscstr, &ecptr); + if ( (*ecptr != '\0') || (ecptr == NULL) /*|| (ecptr != verscstr)*/ || + ((int)(GLCDSKIN_SKIN_VERSION * 100.0) < (int)(currv * 100.0)) + ) + { + return false; + } + return true; +} + + bool StartElem(const std::string & name, std::map<std::string,std::string> & attrs) { //printf("start element: %s\n", name.c_str()); - +// if (context.size() > 0) fprintf(stderr, "context: %s\n", context[context.size() - 1].c_str()); if (context.size() == 0) { if (name == "skin") { ATTRIB_MAN_STRING("version", skin->version); ATTRIB_MAN_STRING("name", skin->title); + ATTRIB_OPT_FUNC("enable", skin->ParseEnable); + + if (! CheckSkinVersion(skin->version) ) { + errorDetail = "skin version '"+ skin->version +"' not supported."; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } } else TAG_ERR_REMAIN("document"); } + else if (name == "condblock") + { + int i = context.size() - 1; + while (i >= 0) { + if (context[i] == "condblock") { + errorDetail = "'condblock' must not be nested in another 'condblock'."; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } + i--; + } + ATTRIB_MAN_STRING("condition", condblock_cond); + } else if (name == "variable") { variable = new cSkinVariable(skin); ATTRIB_MAN_STRING("id", variable->mId); ATTRIB_MAN_FUNC("value", variable->ParseValue); - ATTRIB_OPT_FUNC("condition", variable->ParseCondition); + if (context[context.size() - 1] == "condblock") { + if (attrs.find("condition") != attrs.end()) { + errorDetail = "variable \""+variable->mId+"\" must not contain a condition when context = 'condblock'."; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } else { + if (! variable->ParseCondition(condblock_cond)) { + errorDetail = "Unexpected value \""+ attrs["condition"] +"\" for attribute "+ (std::string)"condition"; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } + } + } else { + ATTRIB_OPT_FUNC("condition", variable->ParseCondition); + } + // if a 'default' value is set, create a second variable w/o condition: will be used if condition is not true + // as variables all have global scope (no matter where defined) and will always be sought from the start of the array, + // the default variable will be inserted _after_ the variable containing the condition. + if (attrs.find("default") != attrs.end()) { + variable_default = new cSkinVariable(skin); + ATTRIB_MAN_STRING("id", variable_default->mId); + ATTRIB_MAN_FUNC("default", variable_default->ParseValue); + } } else if (context[context.size() - 1] == "skin") { @@ -196,6 +258,7 @@ bool StartElem(const std::string & name, std::map<std::string,std::string> & att ATTRIB_OPT_FUNC("width", object->ParseWidth); ATTRIB_OPT_FUNC("height", object->ParseHeight); ATTRIB_OPT_FUNC("condition", object->ParseCondition); + ATTRIB_OPT_STRING("action", object->mAction); if (name == "image") { @@ -203,57 +266,57 @@ bool StartElem(const std::string & name, std::map<std::string,std::string> & att ATTRIB_OPT_FUNC_PARAM("y", object->ParseIntParam, object->mPos1.y); ATTRIB_OPT_FUNC_PARAM("x", object->ParseIntParam, object->mPos2.x); ATTRIB_OPT_FUNC_PARAM("y", object->ParseIntParam, object->mPos2.y); - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); + ATTRIB_OPT_FUNC_PARAM("bgcolor", object->ParseColor, object->mBackgroundColor); ATTRIB_MAN_FUNC("path", object->mPath.Parse); + ATTRIB_OPT_FUNC("loop", object->ParseScrollLoopMode); } else if (name == "text" || name == "scrolltext") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); + ATTRIB_OPT_FUNC_PARAM("bgcolor", object->ParseColor, object->mBackgroundColor); ATTRIB_OPT_FUNC("align", object->ParseAlignment); + ATTRIB_OPT_FUNC("valign", object->ParseVerticalAlignment); ATTRIB_OPT_FUNC("font", object->ParseFontFace); ATTRIB_OPT_BOOL("multiline", object->mMultiline); -#if 0 - if (name == "blink") - { - ATTRIB_OPT_NUMBER("delay", object->mDelay); - - if (object->mDelay == 0) - object->mDelay = 1000; - } - else if (name == "marquee") - { - ATTRIB_OPT_NUMBER("delay", object->mDelay); - - if (object->mDelay == 0) - object->mDelay = 500; - } -#endif + ATTRIB_OPT_FUNC("scrollmode", object->ParseScrollLoopMode); + ATTRIB_OPT_FUNC("scrollspeed", object->ParseScrollSpeed); + ATTRIB_OPT_FUNC("scrolltime", object->ParseScrollTime); + ATTRIB_OPT_STRING("alttext", object->mAltText); + ATTRIB_OPT_FUNC("altcondition", object->ParseAltCondition); + } + else if (name == "button") + { + ATTRIB_OPT_FUNC_PARAM("labelcolor", object->ParseColor, object->mColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mBackgroundColor); + ATTRIB_OPT_FUNC("font", object->ParseFontFace); + ATTRIB_OPT_NUMBER("radius", object->mRadius); } else if (name == "pixel") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); } else if (name == "line") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); } else if (name == "rectangle") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); ATTRIB_OPT_BOOL("filled", object->mFilled); ATTRIB_OPT_NUMBER("radius", object->mRadius); } else if (name == "ellipse" || name == "slope") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); ATTRIB_OPT_BOOL("filled", object->mFilled); ATTRIB_OPT_NUMBER("arc", object->mArc); } else if (name == "progress" || name == "scrollbar") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); ATTRIB_OPT_NUMBER("direction", object->mDirection); ATTRIB_OPT_FUNC("current", object->mCurrent.Parse); ATTRIB_OPT_FUNC("total", object->mTotal.Parse); @@ -284,7 +347,8 @@ bool CharData(const std::string & text) //printf("context: %s\n", context[context.size() - 1].c_str()); if (context[context.size() - 1] == "text" - || context[context.size() - 1] == "scrolltext") + || context[context.size() - 1] == "scrolltext" + || context[context.size() - 1] == "button") { if (!object->mText.Parse(text)) return false; @@ -307,7 +371,13 @@ bool EndElem(const std::string & name) else if (name == "variable") { skin->mVariables.push_back(variable); +//fprintf(stderr, " variable '%s', value: %s\n", variable->mId.c_str(), ((std::string)variable->Value()).c_str()); variable = NULL; + if (variable_default != NULL) { + skin->mVariables.push_back(variable_default); +//fprintf(stderr, " variable default '%s', value: %s\n", variable_default->mId.c_str(), ((std::string)variable_default->Value()).c_str()); + variable_default = NULL; + } } else if (name == "display") { @@ -320,7 +390,7 @@ bool EndElem(const std::string & name) { if (object == NULL) { - printf("rotating parent to object\n"); + //printf("rotating parent to object\n"); object = parents[parents.size() - 1]; parents.pop_back(); } @@ -343,7 +413,7 @@ bool EndElem(const std::string & name) #endif if (parents.size() > 0) { - printf("pushing to parent\n"); + //printf("pushing to parent\n"); cSkinObject *parent = parents[parents.size() - 1]; if (parent->mObjects == NULL) parent->mObjects = new cSkinObjects(); @@ -360,7 +430,7 @@ bool EndElem(const std::string & name) return true; } -cSkin * XmlParse(cSkinConfig & Config, const std::string & Name, const std::string & fileName) +cSkin * XmlParse(cSkinConfig & Config, const std::string & Name, const std::string & fileName, std::string & errorString) { skin = new cSkin(Config, Name); context.clear(); @@ -371,7 +441,13 @@ cSkin * XmlParse(cSkinConfig & Config, const std::string & Name, const std::stri xml.SetCDataCB(CharData); if (xml.Parse() != 0) { - syslog(LOG_ERR, "ERROR: Text2Skin: Parse error in %s, line %d", fileName.c_str(), xml.LineNr()); + char buff[8]; + snprintf(buff, 7, "%d", xml.LineNr()); + syslog(LOG_ERR, "ERROR: graphlcd/skin: Parse error in %s, line %d", fileName.c_str(), xml.LineNr()); + // shorter version outgoing errorString (eg. displaying errorString on the display) + errorString = "Parse error in skin "+Name+", line "+buff; + if (errorDetail != "") + errorString += ":\n"+errorDetail; delete skin; skin = NULL; delete display; @@ -383,6 +459,7 @@ cSkin * XmlParse(cSkinConfig & Config, const std::string & Name, const std::stri cSkin * result = skin; skin = NULL; + errorString = ""; return result; } |