]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/applet/prepifelse.cpp
compilation fix for Watcom
[wxWidgets.git] / contrib / src / applet / prepifelse.cpp
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 /****************************************************************************
45 REMARKS:
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 ****************************************************************************/
50 int ReverseFind(
51 const wxString &tstr,
52 const wxString &str,
53 int start = -1)
54 {
55 wxASSERT( str.GetStringData()->IsValid() );
56
57 // TODO could be made much quicker than that
58 int p = tstr.Len()-str.Len()-1;
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;
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
72 /****************************************************************************
73 PARAMETERS:
74 str - text of #if statement
75
76 RETURNS:
77 true or false depending on how it evaluated
78
79 REMARKS:
80
81 SEE ALSO:
82 wxIfElseVariable
83 ****************************************************************************/
84 bool 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 }
197 /****************************************************************************
198 PARAMETERS:
199 text - HTML to process for if/else blocks
200
201 RETURNS:
202 The string containing the processed HTML
203
204 REMARKS:
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.
210
211 SEE ALSO:
212 wxIfElseVariable
213 ****************************************************************************/
214 wxString wxIfElsePrep::Process(
215 const wxString& text) const
216 {
217 int b;
218 char ft[] = "<!--#if ";
219 char ftend[] = "<!--#endif-->";
220 char ftelse[] = "<!--#else-->";
221 char ftnot[] = "<!--#if not ";
222 char ftnot2[] = "<!--#if !";
223
224 char ftelif[] = "<!--#elif ";
225
226 // make a copy so we can replace text as we go without affecting the original
227 wxString output = text;
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
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-->
291 bool notval = false;
292 int off = 0;
293 int end;
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;
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);
314
315 value = ParseIfStatementValue(tag);
316
317 // Find the end of the tag (<!--#endif-->) and copy it all into the variable code
318 end = ((output.Mid(b)).Lower()).Find(ftend);
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);
327 output.Remove(b, end+strlen(ftend)); // remove the entire #if block from original document
328
329 // Find out if there is an else statement
330 end = (code.Lower()).Find(ftelse);
331 if (end != -1) {
332 if (!value) {
333 // Use the else statement
334 usecode = code.Mid(end+strlen(ftelse));
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
353 FORCE_LINK(ifelsevar)