1. Updates to HTML applet classes in client side include syntax 2. Updates to wxUniversal for OS/2 3. Updates for better palette management on Windows 4. Misc other fixes and changes to fix build system for Watcom 11.0 git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@12045 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
354 lines
12 KiB
C++
354 lines
12 KiB
C++
/****************************************************************************
|
|
*
|
|
* wxWindows HTML Applet Package
|
|
*
|
|
* Copyright (C) 1991-2001 SciTech Software, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* The contents of this file are subject to the wxWindows License
|
|
* Version 3.0 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.wxwindows.org/licence3.txt
|
|
*
|
|
* Software distributed under the License is distributed on an
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Language: ANSI C++
|
|
* Environment: Any
|
|
*
|
|
* Description: This file is the implementation of the Preprocessor object
|
|
* for parsing the <!--#if directive
|
|
*
|
|
****************************************************************************/
|
|
|
|
// For compilers that support precompilation
|
|
#include "wx/wxprec.h"
|
|
#include "wx/html/forcelnk.h"
|
|
|
|
// Include private headers
|
|
#include "wx/applet/prepifelse.h"
|
|
#include "wx/applet/ifelsevar.h"
|
|
|
|
/*---------------------------- Global variables ---------------------------*/
|
|
|
|
|
|
/*----------------------------- Implementation ----------------------------*/
|
|
|
|
/* {SECRET} */
|
|
/****************************************************************************
|
|
REMARKS:
|
|
None of the Reverse Find functions in wxWindows appear to work in a way that
|
|
can be used by our code. This includes the libstr rfind implementations which
|
|
do not correctly pass the given return value.
|
|
****************************************************************************/
|
|
int ReverseFind(
|
|
const wxString &tstr,
|
|
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;
|
|
p--;
|
|
}
|
|
|
|
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
|
|
|
|
RETURNS:
|
|
The string containing the processed HTML
|
|
|
|
REMARKS:
|
|
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
|
|
of this class and access the value of the variable.
|
|
|
|
SEE ALSO:
|
|
wxIfElseVariable
|
|
****************************************************************************/
|
|
wxString wxIfElsePrep::Process(
|
|
const wxString& text) const
|
|
{
|
|
int b;
|
|
char ft[] = "<!--#if ";
|
|
char ftend[] = "<!--#endif-->";
|
|
char ftelse[] = "<!--#else-->";
|
|
char ftnot[] = "<!--#if not ";
|
|
char ftnot2[] = "<!--#if !";
|
|
|
|
char ftelif[] = "<!--#elif ";
|
|
|
|
// make a copy so we can replace text as we go without affecting the original
|
|
wxString output = text;
|
|
|
|
// Avoid duplication of our parsing code by turning any #elif blocks into appropriate
|
|
// else/if blocks
|
|
while ((b = ReverseFind(output.Lower(), ftelif)) != -1) {
|
|
int e;
|
|
// Replace beginning of block
|
|
e = output.find("-->", 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 #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 <!--#endif-->
|
|
bool notval = false;
|
|
int off = 0;
|
|
int end;
|
|
wxString usecode, code;
|
|
wxString cname;
|
|
wxString tag;
|
|
bool value;
|
|
|
|
code = wxString("");
|
|
|
|
// grab the tag and get the name of the variable
|
|
end = (output.Mid(b)).Find("-->");
|
|
if (end == -1) {
|
|
#ifdef CHECKED
|
|
wxMessageBox("wxHTML #if error: Premature end of file while parsing #if.","Error",wxICON_ERROR);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
end += 3;
|
|
// remove the <!--#if and --> 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);
|
|
|
|
value = ParseIfStatementValue(tag);
|
|
|
|
// Find the end of the tag (<!--#endif-->) and copy it all into the variable code
|
|
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);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
code = output.Mid(b, end);
|
|
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(ftelse);
|
|
if (end != -1) {
|
|
if (!value) {
|
|
// Use the else statement
|
|
usecode = code.Mid(end+strlen(ftelse));
|
|
}
|
|
else {
|
|
// Use statement before #else
|
|
usecode = code.Mid(0, end);
|
|
}
|
|
}
|
|
else if (value) {
|
|
// There is no #else statement
|
|
usecode = code;
|
|
}
|
|
|
|
if (usecode != wxString(""))
|
|
output = (output.Mid(0,b) + usecode + output.Mid(b));
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
FORCE_LINK(ifelsevar)
|