]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/applet/prepifelse.cpp
fix for stupid segfault
[wxWidgets.git] / contrib / src / applet / prepifelse.cpp
CommitLineData
716cd410
KB
1/****************************************************************************
2*
3* wxWindows HTML Applet Package
4*
5* Copyright (C) 1991-2001 SciTech Software, Inc.
6* All rights reserved.
7*
8* ========================================================================
9*
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
14*
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.
19*
20* ========================================================================
21*
22* Language: ANSI C++
23* Environment: Any
24*
25* Description: This file is the implementation of the Preprocessor object
26* for parsing the <!--#if directive
27*
28****************************************************************************/
29
30// For compilers that support precompilation
31#include "wx/wxprec.h"
32#include "wx/html/forcelnk.h"
33
34// Include private headers
35#include "wx/applet/prepifelse.h"
36#include "wx/applet/ifelsevar.h"
37
38/*---------------------------- Global variables ---------------------------*/
39
40
41/*----------------------------- Implementation ----------------------------*/
42
43/* {SECRET} */
44/****************************************************************************
45REMARKS:
46None of the Reverse Find functions in wxWindows appear to work in a way that
47can be used by our code. This includes the libstr rfind implementations which
48do not correctly pass the given return value.
49****************************************************************************/
50int ReverseFind(
51 const wxString &tstr,
19193a2c
KB
52 const wxString &str,
53 int start = -1)
716cd410
KB
54{
55 wxASSERT( str.GetStringData()->IsValid() );
56
57 // TODO could be made much quicker than that
58 int p = tstr.Len()-str.Len()-1;
19193a2c
KB
59 int p2 = start-str.Len();
60
61 // if the user supplied a valid start point, use it
62 if (start != -1 && p > p2) p = p2;
716cd410
KB
63 while ( p >= 0 ) {
64 if ( wxStrncmp(tstr.c_str() + p, str.c_str(), str.Len()) == 0 )
65 return p;
66 p--;
67 }
68
69 return -1;
70}
71
19193a2c
KB
72/****************************************************************************
73PARAMETERS:
74str - text of #if statement
75
76RETURNS:
77true or false depending on how it evaluated
78
79REMARKS:
80
81SEE ALSO:
82wxIfElseVariable
83****************************************************************************/
84bool ParseIfStatementValue(wxString &str) {
85
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)
89 int b;
90 while ((b = str.Find('(')) != -1) {
91 int e;
92 // Find the matching parenthesis
93 int nextbeg, nextend;
94 int parencount = 1, min = b+1;
95 do {
96
97 nextbeg = str.find('(', min);
98 nextend = str.find(')', min);
99 if (nextbeg < nextend && nextbeg != wxString::npos) {
100 parencount++;
101 min = nextbeg+1;
102 }
103 else {
104 parencount--;
105 min = nextend+1;
106 }
107
108 if (nextend == wxString::npos) {
109 #ifdef CHECKED
110 wxMessageBox("wxHTML #if\\else error: Unmatched parenthesis in #if expression.","Error",wxICON_ERROR);
111 #endif
112 return true;
113 }
114 // once parencount reaches 0 again we have found our matchin )
115 } while (parencount > 0);
116
117 e = nextend;
118
119 // Extract the expression from the parenthesis block and recurse
120 // to solve it.
121 wxString tag;
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);
127
128 }
129
130 // Remove spaces from left and right
131 str.Trim(false);
132 str.Trim(true);
133
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 ", "||");
138
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)
142 int and, or;
143 and = ReverseFind(str, "&&");
144 or = ReverseFind(str, "||");
145 if ( (and != -1) || (or != -1) ) {
146 wxString tag1, tag2;
147 // handle the rightmost first to force left->right evaluation
148 if (and > or) {
149 return (
150 ParseIfStatementValue(tag2 = str.Mid(and+2)) &&
151 ParseIfStatementValue(tag1 = str.Mid(0, and)) );
152 }
153 else {
154 return (
155 ParseIfStatementValue(tag2 = str.Mid(or+2)) ||
156 ParseIfStatementValue(tag1 = str.Mid(0, or)) );
157 }
158
159 }
160
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
163 bool notval = false;
164
165 // search for a NOT or ! operator
166 if (str.Mid(0, 1) == "!") {
167 str.Remove(0, 1);
168 str.Trim(false); // trim spaces from left
169 notval = true;
170 }
171 else if (str.Mid(0,4).CmpNoCase("NOT ") == 0) {
172 str.Remove(0, 4);
173 str.Trim(false); // trim any extra spaces from left
174 notval = true;
175 }
176
177 // now all we have left is the name of the class or a hardcoded 0 or 1
178
179 if (str == "") {
180 #ifdef CHECKED
181 wxMessageBox("wxHTML #if\\else error: Empty expression in #if\\#elif statement.","Error",wxICON_ERROR);
182 #endif
183 return true;
184 }
185
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;
190
191 // Grab the value from the variable class identified by cname
192 bool value = wxIfElseVariable::FindValue(str);
193 if (notval) value = !value;
194 return value;
195
196}
716cd410
KB
197/****************************************************************************
198PARAMETERS:
199text - HTML to process for if/else blocks
200
201RETURNS:
202The string containing the processed HTML
203
204REMARKS:
19193a2c 205This function replaces #if, #else, #elif, and #endif directives with the text
716cd410
KB
206contained within the blocks, dependant on the value of the given boolean
207variable. The variable is created by making a sub class of wxIfElseVariable.
208Dynamic class construction is used at run time internally to create an instance
209of this class and access the value of the variable.
210
211SEE ALSO:
212wxIfElseVariable
213****************************************************************************/
214wxString wxIfElsePrep::Process(
215 const wxString& text) const
216{
217 int b;
218 char ft[] = "<!--#if ";
19193a2c
KB
219 char ftend[] = "<!--#endif-->";
220 char ftelse[] = "<!--#else-->";
221 char ftnot[] = "<!--#if not ";
505710ca
KB
222 char ftnot2[] = "<!--#if !";
223
19193a2c
KB
224 char ftelif[] = "<!--#elif ";
225
226 // make a copy so we can replace text as we go without affecting the original
716cd410 227 wxString output = text;
19193a2c
KB
228
229 // Avoid duplication of our parsing code by turning any #elif blocks into appropriate
230 // else/if blocks
231 while ((b = ReverseFind(output.Lower(), ftelif)) != -1) {
232 int e;
233 // Replace beginning of block
234 e = output.find("-->", b + strlen(ftelif));
235
236 if (e == wxString::npos) {
237 #ifdef CHECKED
238 wxMessageBox("wxHTML #elif error: Premature end of file while parsing #elif.","Error",wxICON_ERROR);
239 #endif
240 break;
241 }
242
243 // Convert to lower case so find is easy, grab everything after #elif tag
244 wxString remains = (output.Mid(e+strlen("-->"))).Lower();
245
246 // find matching else or endif
247 int nextif, nextendif;
248 int ifcount = 1, min = 0;
249 do {
250 nextif = remains.find(ft, min);
251 nextendif = remains.find(ftend, min);
252 if (nextif < nextendif && nextif != wxString::npos) {
253 ifcount++;
254 min = nextif+1;
255 }
256 else {
257 ifcount--;
258 min = nextendif+1;
259 }
260
261 if (nextendif == wxString::npos) {
262 #ifdef CHECKED
263 wxMessageBox("wxHTML #elif error: Premature end of file before finding #endif.","Error",wxICON_ERROR);
264 #endif
265 break;
266 }
267 // once ifcount reaches 0 again we have found our matchin #endif
268 } while (ifcount > 0);
269
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
273 break;
274 }
275
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) +
281 wxString(ftend) +
282 output.Mid(b+strlen(ftelif)+elifsize+nextendif);
283
284 }
285
286 // Parse out the if else blocks themselves
716cd410 287 while ((b = ReverseFind(output.Lower(), ft)) != -1) {
505710ca 288 // Loop until every #if directive is found
716cd410
KB
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-->
505710ca
KB
291 bool notval = false;
292 int off = 0;
19193a2c 293 int end;
716cd410
KB
294 wxString usecode, code;
295 wxString cname;
296 wxString tag;
297 bool value;
298
299 code = wxString("");
300
301 // grab the tag and get the name of the variable
302 end = (output.Mid(b)).Find("-->");
303 if (end == -1) {
304#ifdef CHECKED
305 wxMessageBox("wxHTML #if error: Premature end of file while parsing #if.","Error",wxICON_ERROR);
306#endif
307 break;
308 }
309
310 end += 3;
19193a2c
KB
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);
716cd410
KB
313 output.Remove(b, end);
314
19193a2c 315 value = ParseIfStatementValue(tag);
716cd410
KB
316
317 // Find the end of the tag (<!--#endif-->) and copy it all into the variable code
19193a2c 318 end = ((output.Mid(b)).Lower()).Find(ftend);
716cd410
KB
319 if (end == -1) {
320#ifdef CHECKED
321 wxMessageBox("wxHTML #if error: Premature end of file while searching for matching #endif.","Error",wxICON_ERROR);
322#endif
323 break;
324 }
325
326 code = output.Mid(b, end);
19193a2c 327 output.Remove(b, end+strlen(ftend)); // remove the entire #if block from original document
716cd410
KB
328
329 // Find out if there is an else statement
19193a2c 330 end = (code.Lower()).Find(ftelse);
716cd410
KB
331 if (end != -1) {
332 if (!value) {
333 // Use the else statement
19193a2c 334 usecode = code.Mid(end+strlen(ftelse));
716cd410
KB
335 }
336 else {
337 // Use statement before #else
338 usecode = code.Mid(0, end);
339 }
340 }
341 else if (value) {
342 // There is no #else statement
343 usecode = code;
344 }
345
346 if (usecode != wxString(""))
347 output = (output.Mid(0,b) + usecode + output.Mid(b));
348 }
349
350 return output;
351}
352
353FORCE_LINK(ifelsevar)