X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d699f48ba33c96c24f7ab3764ad98ded0633c1c5..cb69afe081994cc75654d5813981172fa194f86f:/contrib/src/applet/prepifelse.cpp diff --git a/contrib/src/applet/prepifelse.cpp b/contrib/src/applet/prepifelse.cpp index cc209ce795..7cda90bc5f 100644 --- a/contrib/src/applet/prepifelse.cpp +++ b/contrib/src/applet/prepifelse.cpp @@ -49,12 +49,17 @@ do not correctly pass the given return value. ****************************************************************************/ int ReverseFind( const wxString &tstr, - const wxString &str) + const wxString &str, + int start = -1) { wxASSERT( str.GetStringData()->IsValid() ); // TODO could be made much quicker than that int p = tstr.Len()-str.Len()-1; + int p2 = start-str.Len(); + + // if the user supplied a valid start point, use it + if (start != -1 && p > p2) p = p2; while ( p >= 0 ) { if ( wxStrncmp(tstr.c_str() + p, str.c_str(), str.Len()) == 0 ) return p; @@ -64,6 +69,131 @@ int ReverseFind( return -1; } +/**************************************************************************** +PARAMETERS: +str - text of #if statement + +RETURNS: +true or false depending on how it evaluated + +REMARKS: + +SEE ALSO: +wxIfElseVariable +****************************************************************************/ +bool ParseIfStatementValue(wxString &str) { + + // Find out if the tag has parenthesis + // recursive to parse the text within the parenthesis, + // replacing the text with 1 or 0, (hardcoded true or false) + int b; + while ((b = str.Find('(')) != -1) { + int e; + // Find the matching parenthesis + int nextbeg, nextend; + int parencount = 1, min = b+1; + do { + + nextbeg = str.find('(', min); + nextend = str.find(')', min); + if (nextbeg < nextend && nextbeg != wxString::npos) { + parencount++; + min = nextbeg+1; + } + else { + parencount--; + min = nextend+1; + } + + if (nextend == wxString::npos) { + #ifdef CHECKED + wxMessageBox("wxHTML #if\\else error: Unmatched parenthesis in #if expression.","Error",wxICON_ERROR); + #endif + return true; + } + // once parencount reaches 0 again we have found our matchin ) + } while (parencount > 0); + + e = nextend; + + // Extract the expression from the parenthesis block and recurse + // to solve it. + wxString tag; + tag = str.Mid(b+1, e-b-1); + bool val = ParseIfStatementValue(tag); + // Add extra spaces just in case of NOT(VAL) + if (val) str = str.Mid(0, b) + " 1" + str.Mid(e+1); + else str = str.Mid(0, b) + " 0" + str.Mid(e+1); + + } + + // Remove spaces from left and right + str.Trim(false); + str.Trim(true); + + // Convert text method of operators "AND" and "OR" to c style + // this makes only one special case necessary for each later on + str.Replace(" AND ", "&&"); + str.Replace(" OR ", "||"); + + // We use ReverseFind so that the whole left expression gets evaluated agains + // the right single item, creating a left -> right evaluation + // Search for || operators, recurse to solve (so we don't have to handle special cases here) + int and, or; + and = ReverseFind(str, "&&"); + or = ReverseFind(str, "||"); + if ( (and != -1) || (or != -1) ) { + wxString tag1, tag2; + // handle the rightmost first to force left->right evaluation + if (and > or) { + return ( + ParseIfStatementValue(tag2 = str.Mid(and+2)) && + ParseIfStatementValue(tag1 = str.Mid(0, and)) ); + } + else { + return ( + ParseIfStatementValue(tag2 = str.Mid(or+2)) || + ParseIfStatementValue(tag1 = str.Mid(0, or)) ); + } + + } + + // By the time we get to this place in the function we are guarenteed to have a single + // variable operation, perhaps with a NOT or ! operator + bool notval = false; + + // search for a NOT or ! operator + if (str.Mid(0, 1) == "!") { + str.Remove(0, 1); + str.Trim(false); // trim spaces from left + notval = true; + } + else if (str.Mid(0,4).CmpNoCase("NOT ") == 0) { + str.Remove(0, 4); + str.Trim(false); // trim any extra spaces from left + notval = true; + } + + // now all we have left is the name of the class or a hardcoded 0 or 1 + + if (str == "") { + #ifdef CHECKED + wxMessageBox("wxHTML #if\\else error: Empty expression in #if\\#elif statement.","Error",wxICON_ERROR); + #endif + return true; + } + + // check for hardcoded 0 and 1 cases, (these are used by parenthesis catcher) + // this just decomplicates the recursion algorithm + if (str == "0") return notval; + if (str == "1") return !notval; + + // Grab the value from the variable class identified by cname + bool value = wxIfElseVariable::FindValue(str); + if (notval) value = !value; + return value; + +} /**************************************************************************** PARAMETERS: text - HTML to process for if/else blocks @@ -72,7 +202,7 @@ RETURNS: The string containing the processed HTML REMARKS: -This function replaces #if, #else, and #endif directives with the text +This function replaces #if, #else, #elif, and #endif directives with the text contained within the blocks, dependant on the value of the given boolean variable. The variable is created by making a sub class of wxIfElseVariable. Dynamic class construction is used at run time internally to create an instance @@ -86,14 +216,81 @@ wxString wxIfElsePrep::Process( { int b; char ft[] = ""; + char ftelse[] = ""; + char ftnot[] = "", b + strlen(ftelif)); + + if (e == wxString::npos) { + #ifdef CHECKED + wxMessageBox("wxHTML #elif error: Premature end of file while parsing #elif.","Error",wxICON_ERROR); + #endif + break; + } + + // Convert to lower case so find is easy, grab everything after #elif tag + wxString remains = (output.Mid(e+strlen("-->"))).Lower(); + + // find matching else or endif + int nextif, nextendif; + int ifcount = 1, min = 0; + do { + nextif = remains.find(ft, min); + nextendif = remains.find(ftend, min); + if (nextif < nextendif && nextif != wxString::npos) { + ifcount++; + min = nextif+1; + } + else { + ifcount--; + min = nextendif+1; + } + + if (nextendif == wxString::npos) { + #ifdef CHECKED + wxMessageBox("wxHTML #elif error: Premature end of file before finding #endif.","Error",wxICON_ERROR); + #endif + break; + } + // once ifcount reaches 0 again we have found our matchin #endif + } while (ifcount > 0); + + // If it couldn't be found die gracefully + if (nextendif == wxString::npos) { + // We already displayed a message, just break all the way out + break; + } + + int elifsize = e - (b + strlen(ftelif)) + strlen("-->"); + // Create the #if/else block, removing the #elif code + output = output.Mid(0, b) + + wxString(wxString(ftelse)+wxString(ft)) + + output.Mid(b+strlen(ftelif), elifsize+nextendif) + + wxString(ftend) + + output.Mid(b+strlen(ftelif)+elifsize+nextendif); + + } + + // Parse out the if else blocks themselves while ((b = ReverseFind(output.Lower(), ft)) != -1) { - // Loop until every #echo directive is found + // Loop until every #if directive is found // We search from the end of the string so that #if statements will properly recurse // and we avoid the hassle of matching statements with the correct - int end, c, n; + bool notval = false; + int off = 0; + int end; wxString usecode, code; wxString cname; wxString tag; @@ -111,29 +308,14 @@ wxString wxIfElsePrep::Process( } end += 3; - tag = output.Mid(b, end); + // remove the sections from the tag before passing it on to be parsed + tag = output.Mid(b+strlen(ft), end-strlen(ft)-3); output.Remove(b, end); - c = tag.Find("-->"); - n = c; - - // find the classname - c = (tag.Mid(8, n-8)).Find(" "); - if (c == -1) n -= 8; - else n = c; - cname = tag.Mid(8, n); - - cname.Trim(false); - c = cname.Find("\""); - if (c != -1) cname = cname.Mid(c+1); - c = cname.Find("\""); - if (c != -1) cname = cname.Mid(0, c); - - // Grab the value from the variable class identified by cname - value = wxIfElseVariable::FindValue(cname); + value = ParseIfStatementValue(tag); // Find the end of the tag () and copy it all into the variable code - end = ((output.Mid(b)).Lower()).Find(""); + end = ((output.Mid(b)).Lower()).Find(ftend); if (end == -1) { #ifdef CHECKED wxMessageBox("wxHTML #if error: Premature end of file while searching for matching #endif.","Error",wxICON_ERROR); @@ -142,14 +324,14 @@ wxString wxIfElsePrep::Process( } code = output.Mid(b, end); - output.Remove(b, end+13); // remove the entire #if block from original document + output.Remove(b, end+strlen(ftend)); // remove the entire #if block from original document // Find out if there is an else statement - end = (code.Lower()).Find(""); + end = (code.Lower()).Find(ftelse); if (end != -1) { if (!value) { // Use the else statement - usecode = code.Mid(end+12); + usecode = code.Mid(end+strlen(ftelse)); } else { // Use statement before #else