]>
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 // Include private headers
31 #include "wx/applet/prepifelse.h"
32 #include "wx/applet/ifelsevar.h"
33 #include "wx/applet/echovar.h"
34 #include "wx/string.h"
37 #include "wx/html/forcelnk.h"
39 #include "wx/msgdlg.h"
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 tells if a character is a letter.
75 replace this when wxWindows gets regex library. (without strange licensing
77 ****************************************************************************/
79 char c
, bool acceptspace
= false)
81 if (acceptspace
&& (c
== ' ')) return true;
82 if (c
>= '0' && c
<= '9') return true;
83 return ((c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z') || c
== '_' || c
== '\"' || c
== '\'' );
86 #define IsQuote(c) (c == '\'' || c == '\"')
89 /****************************************************************************
91 tells if a character is a letter.
92 replace this when wxWindows gets regex library. (without strange licensing
94 ****************************************************************************/
99 if (!wxEchoVariable::Exists(var
)) {
100 // TODO: when we implement the set variable, check for a set variable as well
102 wxMessageBox(wxString("wxHTML #if\\else error: Variable ") + var
+ wxString(" not found."),"Error",wxICON_ERROR
);
104 return wxString("0"); // false
107 wxString tmp
= wxEchoVariable::GetValue(var
);
109 if (IsQuote( value
.GetChar(0) ))
110 value
= value
.Mid(1);
111 if (IsQuote(value
.GetChar(value
.Length()-1)))
112 value
= value
.Mid(0,value
.Length()-1);
114 if (tmp
.CmpNoCase(value
) == 0) return wxString("1");
115 return wxString("0");
118 /****************************************************************************
120 str - text of #if statement
123 true or false depending on how it evaluated
126 TODO: rewrite this whole thing using regular expressions when they are done.
130 ****************************************************************************/
131 bool ParseIfStatementValue(
134 // Find out if the tag has parenthesis
135 // recursive to parse the text within the parenthesis,
136 // replacing the text with 1 or 0, (hardcoded true or false)
138 while ((b
= str
.Find('(')) != -1) {
140 // Find the matching parenthesis
141 int nextbeg
, nextend
;
142 int parencount
= 1, min
= b
+1;
144 nextbeg
= str
.find('(', min
);
145 nextend
= str
.find(')', min
);
146 if (nextbeg
< nextend
&& nextbeg
!= wxString::npos
) {
155 if (nextend
== wxString::npos
) {
157 wxMessageBox("wxHTML #if\\else error: Unmatched parenthesis in #if expression.","Error",wxICON_ERROR
);
161 // once parencount reaches 0 again we have found our matchin )
162 } while (parencount
> 0);
166 // Extract the expression from the parenthesis block and recurse
169 tag
= str
.Mid(b
+1, e
-b
-1);
170 bool val
= ParseIfStatementValue(tag
);
171 // Add extra spaces just in case of NOT(VAL)
172 if (val
) str
= str
.Mid(0, b
) + " 1" + str
.Mid(e
+1);
173 else str
= str
.Mid(0, b
) + " 0" + str
.Mid(e
+1);
176 // Remove spaces from left and right
180 // Convert text method of operators "AND" and "OR" to c style
181 // this makes only one special case necessary for each later on
182 str
.Replace(" AND ", "&&");
183 str
.Replace(" OR ", "||");
184 str
.Replace(" EQUALS ", "==");
186 // Check for equals statements
187 // == statements are special because they are evaluated as a single block
189 equ
= str
.find("==");
190 while (equ
!= wxString::npos
) {
192 int begin2
, end2
; // ends of words
196 // remove spaces, find extents
197 while (end
< str
.Length() && str
.GetChar(end
) == ' ')
199 while (begin
>= 0 && str
.GetChar(begin
) == ' ')
203 if (str
.GetChar(end2
) == '\'' || str
.GetChar(end2
) == '\"') {
205 while (end2
< str
.Length() && str
.GetChar(end2
) != '\'' && str
.GetChar(end2
) != '\"' )
210 while (end2
< str
.Length() && IsLetter(str
.GetChar(end2
)))
213 while (begin
>= 0 && IsLetter(str
.GetChar(begin
)))
216 if (begin
< 0) begin
= 0;
218 if (end2
>= str
.Length()) end2
= str
.Length();
220 wxString tmpeq
= GetEquals(str
.Mid(begin
, begin2
-begin
+1), str
.Mid(end
, end2
-end
));
221 str
= str
.Mid(0, begin
) + wxString(" ") + tmpeq
+ wxString(" ") +
223 equ
= str
.find("==");
225 // Remove spaces from left and right
230 // We use ReverseFind so that the whole left expression gets evaluated agains
231 // the right single item, creating a left -> right evaluation
232 // Search for || operators, recurse to solve (so we don't have to handle special cases here)
234 and = ReverseFind(str
, "&&");
235 or = ReverseFind(str
, "||");
236 if ( (and != -1) || (or != -1) ) {
238 // handle the rightmost first to force left->right evaluation
241 ParseIfStatementValue(tag2
= str
.Mid(and+2)) &&
242 ParseIfStatementValue(tag1
= str
.Mid(0, and)) );
246 ParseIfStatementValue(tag2
= str
.Mid(or+2)) ||
247 ParseIfStatementValue(tag1
= str
.Mid(0, or)) );
251 // By the time we get to this place in the function we are guarenteed to have a single
252 // variable operation, perhaps with a NOT or ! operator
255 // search for a NOT or ! operator
256 if (str
.Mid(0, 1) == "!") {
258 str
.Trim(false); // trim spaces from left
261 else if (str
.Mid(0,4).CmpNoCase("NOT ") == 0) {
263 str
.Trim(false); // trim any extra spaces from left
267 // now all we have left is the name of the class or a hardcoded 0 or 1
270 wxMessageBox("wxHTML #if\\else error: Empty expression in #if\\#elif statement.","Error",wxICON_ERROR
);
275 // check for hardcoded 0 and 1 cases, (these are used by parenthesis catcher)
276 // this just decomplicates the recursion algorithm
277 if (str
== "0") return notval
;
278 if (str
== "1") return !notval
;
280 // Grab the value from the variable class identified by cname
281 bool value
= wxIfElseVariable::GetValue(str
);
282 if (notval
) value
= !value
;
286 /****************************************************************************
288 text - HTML to process for if/else blocks
291 The string containing the processed HTML
294 This function replaces #if, #else, #elif, and #endif directives with the text
295 contained within the blocks, dependant on the value of the given boolean
296 variable. The variable is created by making a sub class of wxIfElseVariable.
297 Dynamic class construction is used at run time internally to create an instance
298 of this class and access the value of the variable.
302 ****************************************************************************/
303 wxString
wxIfElsePrep::Process(
304 const wxString
& text
) const
307 char ft
[] = "<!--#if ";
308 char ftend
[] = "<!--#endif-->";
309 char ftelse
[] = "<!--#else-->";
310 char ftnot
[] = "<!--#if not ";
311 char ftnot2
[] = "<!--#if !";
312 char ftelif
[] = "<!--#elif ";
314 // make a copy so we can replace text as we go without affecting the original
315 wxString output
= text
;
317 // Avoid duplication of our parsing code by turning any #elif blocks into appropriate
319 while ((b
= ReverseFind(output
.Lower(), ftelif
)) != -1) {
321 // Replace beginning of block
322 e
= output
.find("-->", b
+ strlen(ftelif
));
324 if (e
== wxString::npos
) {
326 wxMessageBox("wxHTML #elif error: Premature end of file while parsing #elif.","Error",wxICON_ERROR
);
331 // Convert to lower case so find is easy, grab everything after #elif tag
332 wxString remains
= (output
.Mid(e
+strlen("-->"))).Lower();
334 // find matching else or endif
335 int nextif
, nextendif
;
336 int ifcount
= 1, min
= 0;
338 nextif
= remains
.find(ft
, min
);
339 nextendif
= remains
.find(ftend
, min
);
340 if (nextif
< nextendif
&& nextif
!= wxString::npos
) {
349 if (nextendif
== wxString::npos
) {
351 wxMessageBox("wxHTML #elif error: Premature end of file before finding #endif.","Error",wxICON_ERROR
);
355 // once ifcount reaches 0 again we have found our matchin #endif
356 } while (ifcount
> 0);
358 // If it couldn't be found die gracefully
359 if (nextendif
== wxString::npos
) {
360 // We already displayed a message, just break all the way out
364 int elifsize
= e
- (b
+ strlen(ftelif
)) + strlen("-->");
365 // Create the #if/else block, removing the #elif code
366 output
= output
.Mid(0, b
) +
367 wxString(wxString(ftelse
)+wxString(ft
)) +
368 output
.Mid(b
+strlen(ftelif
), elifsize
+nextendif
) +
370 output
.Mid(b
+strlen(ftelif
)+elifsize
+nextendif
);
373 // Parse out the if else blocks themselves
374 while ((b
= ReverseFind(output
.Lower(), ft
)) != -1) {
375 // Loop until every #if directive is found
376 // We search from the end of the string so that #if statements will properly recurse
377 // and we avoid the hassle of matching statements with the correct <!--#endif-->
381 wxString usecode
, code
;
388 // grab the tag and get the name of the variable
389 end
= (output
.Mid(b
)).Find("-->");
392 wxMessageBox("wxHTML #if error: Premature end of file while parsing #if.","Error",wxICON_ERROR
);
398 // remove the <!--#if and --> sections from the tag before passing it on to be parsed
399 tag
= output
.Mid(b
+strlen(ft
), end
-strlen(ft
)-3);
400 output
.Remove(b
, end
);
402 value
= ParseIfStatementValue(tag
);
404 // Find the end of the tag (<!--#endif-->) and copy it all into the variable code
405 end
= ((output
.Mid(b
)).Lower()).Find(ftend
);
408 wxMessageBox("wxHTML #if error: Premature end of file while searching for matching #endif.","Error",wxICON_ERROR
);
413 code
= output
.Mid(b
, end
);
414 output
.Remove(b
, end
+strlen(ftend
)); // remove the entire #if block from original document
416 // Find out if there is an else statement
417 end
= (code
.Lower()).Find(ftelse
);
420 // Use the else statement
421 usecode
= code
.Mid(end
+strlen(ftelse
));
424 // Use statement before #else
425 usecode
= code
.Mid(0, end
);
429 // There is no #else statement
433 if (usecode
!= wxString(""))
434 output
= (output
.Mid(0,b
) + usecode
+ output
.Mid(b
));
440 FORCE_LINK(ifelsevar
)