summaryrefslogtreecommitdiff
path: root/glcdskin/string.c
diff options
context:
space:
mode:
Diffstat (limited to 'glcdskin/string.c')
-rw-r--r--glcdskin/string.c155
1 files changed, 129 insertions, 26 deletions
diff --git a/glcdskin/string.c b/glcdskin/string.c
index dc9d9dc..3966449 100644
--- a/glcdskin/string.c
+++ b/glcdskin/string.c
@@ -55,18 +55,23 @@ std::string tSkinToken::Token(const tSkinToken & Token)
return result;
}
+#if 0
cSkinString::tStringList cSkinString::mStrings;
+#endif
cSkinString::cSkinString(cSkinObject *Parent, bool Translate)
: mObject(Parent),
mSkin(Parent->Skin()),
mTranslate(Translate)
{
+#if 0
mStrings.push_back(this);
+#endif
}
cSkinString::~cSkinString()
{
+#if 0
tStringList::iterator it = mStrings.begin();
for (; it != mStrings.end(); ++it) {
if ((*it) == this) {
@@ -74,8 +79,10 @@ cSkinString::~cSkinString()
break;
}
}
+#endif
}
+#if 0
void cSkinString::Reparse(void)
{
tStringList::iterator it = mStrings.begin();
@@ -84,6 +91,14 @@ void cSkinString::Reparse(void)
(*it)->Parse((*it)->mOriginal, true);
}
}
+#endif
+
+
+// copied from xml.c (should be valid for parsing variable names too ...)
+static bool IsTokenChar(bool start, int c) {
+ return isalpha(c) || c == '_' || (!start && isdigit(c));
+}
+
bool cSkinString::Parse(const std::string & Text, bool Translate)
{
@@ -93,16 +108,6 @@ bool cSkinString::Parse(const std::string & Text, bool Translate)
bool inAttrib = false;
int offset = 0;
- if (trans[0] == '#')
- {
- cSkinVariable * variable = mSkin->GetVariable(trans.substr(1));
- if (variable)
- {
- trans = (std::string) variable->Value();
- syslog(LOG_ERR, "string variable %s", trans.c_str());
- }
- }
-
//Dprintf("parsing: %s\n", Text.c_str());
mOriginal = Text;
mText = "";
@@ -113,16 +118,39 @@ bool cSkinString::Parse(const std::string & Text, bool Translate)
for (; *ptr; ++ptr) {
if (inToken && *ptr == '\\') {
if (*(ptr + 1) == '\0') {
- syslog(LOG_ERR, "ERROR: Stray \\ in token attribute\n");
+ syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Stray \\ in token attribute\n");
return false;
}
++ptr;
continue;
}
+ else if (*ptr == '#') {
+ if (inToken) {
+ syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Unexpected '#' in token");
+ return false;
+ }
+
+ mText.append(last, ptr - last);
+
+ bool isStartChar = true;
+ const char * varNameStart = ptr;
+ ptr++;
+ while (*ptr && IsTokenChar(isStartChar, *ptr)) {
+ isStartChar = false;
+ ptr++;
+ offset++;
+ }
+ // add #VARNAME#
+ mText.append(varNameStart, (ptr - varNameStart));
+ mText.append("#");
+ offset +=2; // adds two '#' -> fix offset
+ ptr--; // we'd be at the correct position now but the for-loop does a ++ptr -> fix it by stepping back one char
+ last = ptr + 1;
+ }
else if (*ptr == '{') {
if (inToken) {
- syslog(LOG_ERR, "ERROR: Unexpected '{' in token");
+ syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Unexpected '{' in token");
return false;
}
@@ -132,13 +160,13 @@ bool cSkinString::Parse(const std::string & Text, bool Translate)
}
else if (*ptr == '}' || (inToken && *ptr == ':')) {
if (!inToken) {
- syslog(LOG_ERR, "ERROR: Unexpected '}' outside of token");
+ syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Unexpected '}' outside of token");
return false;
}
if (inAttrib) {
if (*ptr == ':') {
- syslog(LOG_ERR, "ERROR: Unexpected ':' inside of token attribute");
+ syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Unexpected ':' inside of token attribute");
return false;
}
@@ -179,12 +207,14 @@ bool cSkinString::Parse(const std::string & Text, bool Translate)
{
std::string tmp;
tmp.assign(last, ptr - last);
- tSkinToken token(mSkin->Config().GetTokenId(tmp), tmp, offset, "");
- mTokens.push_back(token);
+ if (tmp != "") { // ignore empty token
+ tSkinToken token(mSkin->Config().GetTokenId(tmp), tmp, offset, "");
+ mTokens.push_back(token);
+ }
}
else
{
- syslog(LOG_ERR, "ERROR: Unexpected token {%.*s}", (int)(ptr - last), last);
+ syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Unexpected token {%.*s}", (int)(ptr - last), last);
return false;
}
@@ -201,7 +231,7 @@ bool cSkinString::Parse(const std::string & Text, bool Translate)
}
if (inToken) {
- syslog(LOG_ERR, "ERROR: Expecting '}' in token");
+ syslog(LOG_ERR, "ERROR: graphlcd/skin/string: Expecting '}' in token");
return false;
}
@@ -214,19 +244,92 @@ bool cSkinString::Parse(const std::string & Text, bool Translate)
cType cSkinString::Evaluate(void) const
{
- std::string result;
- int offset = 0;
-
if (mText.length() == 0 && mTokens.size() == 1)
return mSkin->Config().GetToken(mTokens[0]);
- for (uint32_t i = 0; i < mTokens.size(); ++i) {
- result.append(mText.c_str() + offset, mTokens[i].Offset - offset);
- result.append(mSkin->Config().GetToken(mTokens[i]));
+ std::string result_raw = "";
+ int offset = 0;
+ for (uint32_t i = 0; i < mTokens.size(); i++) {
+ result_raw.append(mText.substr(offset, mTokens[i].Offset - offset) );
+ result_raw.append(mSkin->Config().GetToken(mTokens[i]));
offset = mTokens[i].Offset;
}
- result.append(mText.c_str() + offset);
- return result;
+ result_raw.append(mText.c_str() + offset);
+
+ // replace variable placeholders (#VARNAME#) with corresponding values
+ std::string result_trans = "";
+ size_t idxstart = 0, idxend = 0;
+ size_t pos = 0;
+ while ( (idxstart=result_raw.find("#", idxstart)) != std::string::npos ) {
+ result_trans.append(result_raw.substr(pos, idxstart-pos));
+ idxend = result_raw.find("#", idxstart+1);
+ if (idxend != std::string::npos) {
+ cSkinVariable * variable = mSkin->GetVariable(result_raw.substr(idxstart+1, idxend-idxstart-1));
+ if (variable) {
+ std::string val = (std::string) variable->Value();
+
+ // if value of variable contains token definions: reparse value
+ if (val.find("{") != std::string::npos) {
+ cSkinString *result = new cSkinString(Object(), false);
+ if (result->Parse(val)) {
+ val = (std::string) result->Evaluate();
+ }
+ delete result;
+ }
+ result_trans.append (val);
+ // syslog(LOG_ERR, "string variable %s", trans.c_str());
+ } else {
+ result_trans.append (result_raw.substr(idxstart, idxend-idxstart)); // no variable found: print as raw text
+ }
+ idxstart = idxend+1;
+ pos = idxstart;
+ } else {
+ result_trans.append ("#"); // no closing '#' -> print # as raw text
+ idxstart ++;
+ pos = idxstart;
+ }
+ }
+ result_trans.append(result_raw.substr(pos));
+
+ // re-evaluate resulting string
+ if ((mText.size() > 0) && mText[0] != '#' && mObject != NULL ) {
+ cSkinFunction *result = new cSkinFunction(mObject);
+ if (result->Parse(result_trans, true)) {
+ std::string result_rescan = (std::string)result->Evaluate();
+ if (result_rescan != "")
+ result_trans = result_rescan;
+ }
+ delete result;
+ }
+
+ // look for $(..)$-expressions
+ result_raw = result_trans;
+ result_trans = "";
+ idxstart = 0;
+ pos = 0;
+ bool err = false;
+ while ( !err && ((idxstart = result_raw.find("$(", idxstart)) != std::string::npos) ) {
+ result_trans.append (result_raw.substr(pos, idxstart - pos) );
+ idxend = result_raw.find(")$", idxstart + 2);
+ if ( idxend == std::string::npos ) { // no $) found: ignore leading $( and pass rest of whole string unparsed
+ result_trans.append(result_raw.substr(pos));
+ err = true;
+ } else {
+ std::string func = result_raw.substr( idxstart + 2, idxend - idxstart - 2 );
+ cSkinFunction *result = new cSkinFunction(mObject);
+ if (result->Parse(func, true)) {
+ std::string result_rescan = (std::string)result->Evaluate();
+ if (result_rescan != "")
+ result_trans.append( result_rescan );
+ }
+ delete result;
+
+ idxstart = idxend + 2;
+ pos = idxstart;
+ }
+ }
+ result_trans.append( result_raw.substr(pos) );
+ return result_trans;
}
} // end of namespace