Start implementation of MsiEvaluateConditionA/W.
[wine] / dlls / msi / cond.y
1 %{
2
3 /*
4  * Implementation of the Microsoft Installer (msi.dll)
5  *
6  * Copyright 2003 Mike McCormack for CodeWeavers
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33
34 #include "msi.h"
35 #include "msiquery.h"
36
37 #define YYLEX_PARAM info
38 #define YYPARSE_PARAM info
39
40 static int COND_error(char *str);
41
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43
44 typedef struct tag_yyinput
45 {
46     MSIHANDLE hInstall;
47     LPCWSTR str;
48     INT    n;
49     INT    start;
50     MSICONDITION result;
51 } COND_input;
52
53 static LPWSTR COND_GetString( COND_input *info );
54 static int COND_lex( void *COND_lval, COND_input *info);
55
56 typedef INT (*comp_int)(INT a, INT b);
57
58 static INT comp_lt(INT a, INT b);
59 static INT comp_gt(INT a, INT b);
60 static INT comp_le(INT a, INT b);
61 static INT comp_ge(INT a, INT b);
62 static INT comp_eq(INT a, INT b);
63 static INT comp_ne(INT a, INT b);
64
65 %}
66
67 %pure-parser
68
69 %union
70 {
71     LPWSTR    string;
72     INT       value;
73     comp_int  fn_comp_int;
74 }
75
76 %token COND_SPACE COND_EOF COND_SPACE
77 %token COND_OR COND_AND COND_NOT
78 %token COND_LT COND_GT COND_LE COND_GE COND_EQ COND_NE
79 %token COND_LPAR COND_RPAR
80 %token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
81 %token COND_IDENT COND_NUMBER
82
83 %nonassoc COND_EOF COND_ERROR
84
85 %type <value> expression boolean_term boolean_factor term value symbol integer
86 %type <string> identifier
87 %type <fn_comp_int> comparison_op
88
89 %%
90
91 condition:
92     expression
93         {
94             COND_input* cond = (COND_input*) info;
95             cond->result = $1;
96         }
97     ;
98
99 expression:
100     boolean_term 
101         {
102             $$ = $1;
103         }
104   | boolean_term COND_OR expression
105         {
106             $$ = $1 || $3;
107         }
108     ;
109
110 boolean_term:
111     boolean_factor
112         {
113             $$ = $1;
114         }
115   | boolean_factor COND_AND term
116         {
117             $$ = $1 && $3;
118         }
119     ;
120
121 boolean_factor:
122     term
123         {
124             $$ = $1;
125         }
126   | COND_NOT term
127         {
128             $$ = ! $2;
129         }
130     ;
131
132 term:
133     value
134         {
135             $$ = $1;
136         }
137   | value comparison_op value
138         {
139             $$ = $2( $1, $3 );
140         }
141   | COND_LPAR expression COND_RPAR
142         {
143             $$ = $2;
144         }
145     ;
146
147 comparison_op:
148     COND_LT
149         {
150             $$ = comp_lt;
151         }
152   | COND_GT
153         {
154             $$ = comp_gt;
155         }
156   | COND_LE
157         {
158             $$ = comp_le;
159         }
160   | COND_GE
161         {
162             $$ = comp_ge;
163         }
164   | COND_EQ
165         {
166             $$ = comp_eq;
167         }
168   | COND_NE
169         {
170             $$ = comp_ne;
171         }
172     ;
173
174 value:
175     symbol
176         {
177             $$ = $1;
178         }
179   | integer
180         {
181             $$ = $1;
182         }
183     ;
184
185 symbol:
186     COND_DOLLARS identifier
187         {
188             COND_input* cond = (COND_input*) info;
189             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
190       
191             MsiGetComponentStateW(cond->hInstall, $2, &install, &action );
192             $$ = action;
193         }
194   | COND_QUESTION identifier
195         {
196             COND_input* cond = (COND_input*) info;
197             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
198       
199             MsiGetComponentStateW(cond->hInstall, $2, &install, &action );
200             $$ = install;
201         }
202   | COND_AMPER identifier
203         {
204             COND_input* cond = (COND_input*) info;
205             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
206       
207             MsiGetFeatureStateW(cond->hInstall, $2, &install, &action );
208             $$ = action;
209         }
210   | COND_EXCLAM identifier
211         {
212             COND_input* cond = (COND_input*) info;
213             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
214       
215             MsiGetFeatureStateW(cond->hInstall, $2, &install, &action );
216             $$ = install;
217         }
218     ;
219
220 identifier:
221     COND_IDENT
222         {
223             COND_input* cond = (COND_input*) info;
224             $$ = COND_GetString(cond);
225             if( !$$ )
226                 YYABORT;
227         }
228   | COND_PERCENT identifier
229         {
230             UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
231             if( len++ )
232             {
233                 $$ = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
234                 if( $$ )
235                     GetEnvironmentVariableW( $2, $$, len );
236             }
237             HeapFree( GetProcessHeap(), 0, $2 );
238         }
239     ;
240
241 integer:
242     COND_NUMBER
243         {
244             COND_input* cond = (COND_input*) info;
245             LPWSTR szNum = COND_GetString(cond);
246             if( !szNum )
247                 YYABORT;
248             $$ = atoiW( szNum );
249             HeapFree( GetProcessHeap(), 0, szNum );
250         }
251     ;
252
253 %%
254
255 static INT comp_lt(INT a, INT b)
256 {
257     return (a < b);
258 }
259
260 static INT comp_gt(INT a, INT b)
261 {
262     return (a > b);
263 }
264
265 static INT comp_le(INT a, INT b)
266 {
267     return (a <= b);
268 }
269
270 static INT comp_ge(INT a, INT b)
271 {
272     return (a >= b);
273 }
274
275 static INT comp_eq(INT a, INT b)
276 {
277     return (a == b);
278 }
279
280 static INT comp_ne(INT a, INT b)
281 {
282     return (a != b);
283 }
284
285
286 static int COND_IsAlpha( WCHAR x )
287 {
288     return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) ||
289             ( ( x >= 'a' ) && ( x <= 'z' ) ) );
290 }
291
292 static int COND_IsNumber( WCHAR x )
293 {
294     return( ( x >= '0' ) && ( x <= '9' ) );
295 }
296
297 static int COND_IsIdent( WCHAR x )
298 {
299     return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) );
300 }
301
302 static int COND_lex( void *COND_lval, COND_input *cond )
303 {
304     WCHAR ch;
305
306     cond->start = cond->n;
307     ch = cond->str[cond->n];
308     if( !ch )
309         return COND_EOF;
310     cond->n++;
311
312     switch( ch )
313     {
314     case '(': return COND_LPAR;
315     case ')': return COND_RPAR;
316     case '&': return COND_AMPER;
317     case '!': return COND_EXCLAM;
318     case '$': return COND_DOLLARS;
319     case '?': return COND_QUESTION;
320     case '%': return COND_PERCENT;
321     case ' ': return COND_SPACE;
322     }
323
324     if( COND_IsAlpha( ch ) )
325     {
326         ch = cond->str[cond->n];
327         while( COND_IsIdent( ch ) )
328             ch = cond->str[cond->n++];
329         return COND_IDENT;
330     }
331
332     if( COND_IsNumber( ch ) )
333     {
334         ch = cond->str[cond->n];
335         while( COND_IsNumber( ch ) )
336             ch = cond->str[cond->n++];
337         return COND_NUMBER;
338     }
339
340     return COND_ERROR;
341 }
342
343 static LPWSTR COND_GetString( COND_input *cond )
344 {
345     int len;
346     LPWSTR str;
347
348     len = cond->n - cond->start;
349     str = HeapAlloc( GetProcessHeap(), 0, (len+1) * sizeof (WCHAR) );
350     if( str )
351         strncpyW( str, &cond->str[cond->start], len );
352     return str;
353 }
354
355 static int COND_error(char *str)
356 {
357     return 0;
358 }
359
360 MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition )
361 {
362     COND_input cond;
363     MSICONDITION r;
364
365     cond.hInstall = hInstall;
366     cond.str   = szCondition;
367     cond.n     = 0;
368     cond.start = 0;
369     cond.result = MSICONDITION_ERROR;
370     
371     if( !COND_parse( &cond ) )
372         r = cond.result;
373     else
374         r = MSICONDITION_ERROR;
375
376     return r;
377 }
378
379 MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition )
380 {
381     LPWSTR szwCond = NULL;
382     MSICONDITION r;
383
384     if( szCondition )
385     {
386         UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 );
387         szwCond = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
388         MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len );
389     }
390
391     r = MsiEvaluateConditionW( hInstall, szwCond );
392
393     if( szwCond )
394         HeapFree( GetProcessHeap(), 0, szwCond );
395
396     return r;
397 }