]>
git.saurik.com Git - wxWidgets.git/blob - contrib/src/applet/prepifelse.cpp
1 /****************************************************************************
3 * wxWindows HTML Applet Package
5 * Copyright (C) 1991-2001 SciTech Software, Inc.
8 * ========================================================================
10 * The contents of this file are subject to the wxWindows License
11 * Version 3.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.wxwindows.org/licence3.txt
15 * Software distributed under the License is distributed on an
16 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17 * implied. See the License for the specific language governing
18 * rights and limitations under the License.
20 * ========================================================================
25 * Description: This file is the implementation of the Preprocessor object
26 * for parsing the <!--#if directive
28 ****************************************************************************/
30 // For compilers that support precompilation
31 #include "wx/wxprec.h"
32 #include "wx/html/forcelnk.h"
34 // Include private headers
35 #include "wx/applet/prepifelse.h"
36 #include "wx/applet/ifelsevar.h"
38 /*---------------------------- Global variables ---------------------------*/
41 /*----------------------------- Implementation ----------------------------*/
44 /****************************************************************************
46 None of the Reverse Find functions in wxWindows appear to work in a way that
47 can be used by our code. This includes the libstr rfind implementations which
48 do not correctly pass the given return value.
49 ****************************************************************************/
55 wxASSERT( str
.GetStringData()->IsValid() );
57 // TODO could be made much quicker than that
58 int p
= tstr
.Len()-str
.Len()-1;
59 int p2
= start
-str
.Len();
61 // if the user supplied a valid start point, use it
62 if (start
!= -1 && p
> p2
) p
= p2
;
64 if ( wxStrncmp(tstr
.c_str() + p
, str
.c_str(), str
.Len()) == 0 )
72 /****************************************************************************
74 str - text of #if statement
77 true or false depending on how it evaluated
83 ****************************************************************************/
84 bool ParseIfStatementValue(wxString
&str
) {
86 // Find out if the tag has parenthesis
87 // recursive to parse the text within the parenthesis,
88 // replacing the text with 1 or 0, (hardcoded true or false)
90 while ((b
= str
.Find('(')) != -1) {
92 // Find the matching parenthesis
94 int parencount
= 1, min
= b
+1;
97 nextbeg
= str
.find('(', min
);
98 nextend
= str
.find(')', min
);
99 if (nextbeg
< nextend
&& nextbeg
!= wxString::npos
) {
108 if (nextend
== wxString::npos
) {
110 wxMessageBox("wxHTML #if\\else error: Unmatched parenthesis in #if expression.","Error",wxICON_ERROR
);
114 // once parencount reaches 0 again we have found our matchin )
115 } while (parencount
> 0);
119 // Extract the expression from the parenthesis block and recurse
122 tag
= str
.Mid(b
+1, e
-b
-1);
123 bool val
= ParseIfStatementValue(tag
);
124 // Add extra spaces just in case of NOT(VAL)
125 if (val
) str
= str
.Mid(0, b
) + " 1" + str
.Mid(e
+1);
126 else str
= str
.Mid(0, b
) + " 0" + str
.Mid(e
+1);
130 // Remove spaces from left and right
134 // Convert text method of operators "AND" and "OR" to c style
135 // this makes only one special case necessary for each later on
136 str
.Replace(" AND ", "&&");
137 str
.Replace(" OR ", "||");
139 // We use ReverseFind so that the whole left expression gets evaluated agains
140 // the right single item, creating a left -> right evaluation
141 // Search for || operators, recurse to solve (so we don't have to handle special cases here)
143 and = ReverseFind(str
, "&&");
144 or = ReverseFind(str
, "||");
145 if ( (and != -1) || (or != -1) ) {
147 // handle the rightmost first to force left->right evaluation
150 ParseIfStatementValue(tag2
= str
.Mid(and+2)) &&
151 ParseIfStatementValue(tag1
= str
.Mid(0, and)) );
155 ParseIfStatementValue(tag2
= str
.Mid(or+2)) ||
156 ParseIfStatementValue(tag1
= str
.Mid(0, or)) );
161 // By the time we get to this place in the function we are guarenteed to have a single
162 // variable operation, perhaps with a NOT or ! operator
165 // search for a NOT or ! operator
166 if (str
.Mid(0, 1) == "!") {
168 str
.Trim(false); // trim spaces from left
171 else if (str
.Mid(0,4).CmpNoCase("NOT ") == 0) {
173 str
.Trim(false); // trim any extra spaces from left
177 // now all we have left is the name of the class or a hardcoded 0 or 1
181 wxMessageBox("wxHTML #if\\else error: Empty expression in #if\\#elif statement.","Error",wxICON_ERROR
);
186 // check for hardcoded 0 and 1 cases, (these are used by parenthesis catcher)
187 // this just decomplicates the recursion algorithm
188 if (str
== "0") return notval
;
189 if (str
== "1") return !notval
;
191 // Grab the value from the variable class identified by cname
192 bool value
= wxIfElseVariable::FindValue(str
);
193 if (notval
) value
= !value
;
197 /****************************************************************************
199 text - HTML to process for if/else blocks
202 The string containing the processed HTML
205 This function replaces #if, #else, #elif, and #endif directives with the text
206 contained within the blocks, dependant on the value of the given boolean
207 variable. The variable is created by making a sub class of wxIfElseVariable.
208 Dynamic class construction is used at run time internally to create an instance
209 of this class and access the value of the variable.
213 ****************************************************************************/
214 wxString
wxIfElsePrep::Process(
215 const wxString
& text
) const
218 char ft
[] = "<!--#if ";
219 char ftend
[] = "<!--#endif-->";
220 char ftelse
[] = "<!--#else-->";
221 char ftnot
[] = "<!--#if not ";
222 char ftnot2
[] = "<!--#if !";
224 char ftelif
[] = "<!--#elif ";
226 // make a copy so we can replace text as we go without affecting the original
227 wxString output
= text
;
229 // Avoid duplication of our parsing code by turning any #elif blocks into appropriate
231 while ((b
= ReverseFind(output
.Lower(), ftelif
)) != -1) {
233 // Replace beginning of block
234 e
= output
.find("-->", b
+ strlen(ftelif
));
236 if (e
== wxString::npos
) {
238 wxMessageBox("wxHTML #elif error: Premature end of file while parsing #elif.","Error",wxICON_ERROR
);
243 // Convert to lower case so find is easy, grab everything after #elif tag
244 wxString remains
= (output
.Mid(e
+strlen("-->"))).Lower();
246 // find matching else or endif
247 int nextif
, nextendif
;
248 int ifcount
= 1, min
= 0;
250 nextif
= remains
.find(ft
, min
);
251 nextendif
= remains
.find(ftend
, min
);
252 if (nextif
< nextendif
&& nextif
!= wxString::npos
) {
261 if (nextendif
== wxString::npos
) {
263 wxMessageBox("wxHTML #elif error: Premature end of file before finding #endif.","Error",wxICON_ERROR
);
267 // once ifcount reaches 0 again we have found our matchin #endif
268 } while (ifcount
> 0);
270 // If it couldn't be found die gracefully
271 if (nextendif
== wxString::npos
) {
272 // We already displayed a message, just break all the way out
276 int elifsize
= e
- (b
+ strlen(ftelif
)) + strlen("-->");
277 // Create the #if/else block, removing the #elif code
278 output
= output
.Mid(0, b
) +
279 wxString(wxString(ftelse
)+wxString(ft
)) +
280 output
.Mid(b
+strlen(ftelif
), elifsize
+nextendif
) +
282 output
.Mid(b
+strlen(ftelif
)+elifsize
+nextendif
);
286 // Parse out the if else blocks themselves
287 while ((b
= ReverseFind(output
.Lower(), ft
)) != -1) {
288 // Loop until every #if directive is found
289 // We search from the end of the string so that #if statements will properly recurse
290 // and we avoid the hassle of matching statements with the correct <!--#endif-->
294 wxString usecode
, code
;
301 // grab the tag and get the name of the variable
302 end
= (output
.Mid(b
)).Find("-->");
305 wxMessageBox("wxHTML #if error: Premature end of file while parsing #if.","Error",wxICON_ERROR
);
311 // remove the <!--#if and --> sections from the tag before passing it on to be parsed
312 tag
= output
.Mid(b
+strlen(ft
), end
-strlen(ft
)-3);
313 output
.Remove(b
, end
);
315 value
= ParseIfStatementValue(tag
);
317 // Find the end of the tag (<!--#endif-->) and copy it all into the variable code
318 end
= ((output
.Mid(b
)).Lower()).Find(ftend
);
321 wxMessageBox("wxHTML #if error: Premature end of file while searching for matching #endif.","Error",wxICON_ERROR
);
326 code
= output
.Mid(b
, end
);
327 output
.Remove(b
, end
+strlen(ftend
)); // remove the entire #if block from original document
329 // Find out if there is an else statement
330 end
= (code
.Lower()).Find(ftelse
);
333 // Use the else statement
334 usecode
= code
.Mid(end
+strlen(ftelse
));
337 // Use statement before #else
338 usecode
= code
.Mid(0, end
);
342 // There is no #else statement
346 if (usecode
!= wxString(""))
347 output
= (output
.Mid(0,b
) + usecode
+ output
.Mid(b
));
353 FORCE_LINK(ifelsevar
)