Add missing semicolons that caused compile trouble on FreeBSD.
[wine/multimedia.git] / dlls / msi / cond.y
blob1d55ac3997eecb73f3aa8f9e0e7dd731c00cd727
1 %{
3 /*
4 * Implementation of the Microsoft Installer (msi.dll)
6 * Copyright 2003 Mike McCormack for CodeWeavers
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.
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.
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
23 #include "config.h"
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
35 #include "msi.h"
36 #include "msiquery.h"
37 #include "msipriv.h"
38 #include "action.h"
40 #define YYLEX_PARAM info
41 #define YYPARSE_PARAM info
43 static int COND_error(const char *str);
45 WINE_DEFAULT_DEBUG_CHANNEL(msi);
47 typedef struct tag_yyinput
49 MSIPACKAGE *package;
50 LPCWSTR str;
51 INT n;
52 MSICONDITION result;
53 } COND_input;
55 struct cond_str {
56 LPCWSTR data;
57 INT len;
60 static LPWSTR COND_GetString( struct cond_str *str );
61 static LPWSTR COND_GetLiteral( struct cond_str *str );
62 static int COND_lex( void *COND_lval, COND_input *info);
63 static const WCHAR szEmpty[] = { 0 };
65 static INT compare_int( INT a, INT operator, INT b );
66 static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b );
68 static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b )
70 INT r;
72 r = compare_string( a, op, b );
73 msi_free( a );
74 msi_free( b );
75 return r;
80 %pure-parser
82 %union
84 struct cond_str str;
85 LPWSTR string;
86 INT value;
89 %token COND_SPACE COND_EOF COND_SPACE
90 %token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV
91 %token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE
92 %token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE
93 %token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS
94 %token COND_ILHS COND_IRHS COND_LHS COND_RHS
95 %token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
96 %token <str> COND_IDENT <str> COND_NUMBER <str> COND_LITER
98 %nonassoc COND_ERROR COND_EOF
100 %type <value> expression boolean_term boolean_factor
101 %type <value> value_i integer operator
102 %type <string> identifier symbol_s value_s literal
106 condition:
107 expression
109 COND_input* cond = (COND_input*) info;
110 cond->result = $1;
112 | /* empty */
114 COND_input* cond = (COND_input*) info;
115 cond->result = MSICONDITION_NONE;
119 expression:
120 boolean_term
122 $$ = $1;
124 | expression COND_OR boolean_term
126 $$ = $1 || $3;
128 | expression COND_IMP boolean_term
130 $$ = !$1 || $3;
132 | expression COND_XOR boolean_term
134 $$ = ( $1 || $3 ) && !( $1 && $3 );
136 | expression COND_EQV boolean_term
138 $$ = ( $1 && $3 ) || ( !$1 && !$3 );
142 boolean_term:
143 boolean_factor
145 $$ = $1;
147 | boolean_term COND_AND boolean_factor
149 $$ = $1 && $3;
153 boolean_factor:
154 COND_NOT boolean_factor
156 $$ = $2 ? 0 : 1;
158 | value_i
160 $$ = $1 ? 1 : 0;
162 | value_s
164 $$ = ($1 && $1[0]) ? 1 : 0;
166 | value_i operator value_i
168 $$ = compare_int( $1, $2, $3 );
170 | symbol_s operator value_i
172 $$ = compare_int( $1 ? atoiW($1) : 0, $2, $3 );
174 | value_i operator symbol_s
176 $$ = compare_int( $1, $2, $3 ? atoiW($3) : 0 );
178 | symbol_s operator symbol_s
180 $$ = compare_and_free_strings( $1, $2, $3 );
182 | symbol_s operator literal
184 $$ = compare_and_free_strings( $1, $2, $3 );
186 | literal operator symbol_s
188 $$ = compare_and_free_strings( $1, $2, $3 );
190 | literal operator literal
192 $$ = compare_and_free_strings( $1, $2, $3 );
194 | literal operator value_i
196 $$ = 0;
198 | value_i operator literal
200 $$ = 0;
202 | COND_LPAR expression COND_RPAR
204 $$ = $2;
208 operator:
209 /* common functions */
210 COND_EQ { $$ = COND_EQ; }
211 | COND_NE { $$ = COND_NE; }
212 | COND_LT { $$ = COND_LT; }
213 | COND_GT { $$ = COND_GT; }
214 | COND_LE { $$ = COND_LE; }
215 | COND_GE { $$ = COND_GE; }
216 | COND_SS { $$ = COND_SS; }
217 | COND_IEQ { $$ = COND_IEQ; }
218 | COND_INE { $$ = COND_INE; }
219 | COND_ILT { $$ = COND_ILT; }
220 | COND_IGT { $$ = COND_IGT; }
221 | COND_ILE { $$ = COND_ILE; }
222 | COND_IGE { $$ = COND_IGE; }
223 | COND_ISS { $$ = COND_ISS; }
224 | COND_LHS { $$ = COND_LHS; }
225 | COND_RHS { $$ = COND_RHS; }
226 | COND_ILHS { $$ = COND_ILHS; }
227 | COND_IRHS { $$ = COND_IRHS; }
230 value_s:
231 symbol_s
233 $$ = $1;
235 | literal
237 $$ = $1;
241 literal:
242 COND_LITER
244 $$ = COND_GetLiteral(&$1);
245 if( !$$ )
246 YYABORT;
250 value_i:
251 integer
253 $$ = $1;
255 | COND_DOLLARS identifier
257 COND_input* cond = (COND_input*) info;
258 INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
260 MSI_GetComponentStateW(cond->package, $2, &install, &action );
261 $$ = action;
262 msi_free( $2 );
264 | COND_QUESTION identifier
266 COND_input* cond = (COND_input*) info;
267 INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
269 MSI_GetComponentStateW(cond->package, $2, &install, &action );
270 $$ = install;
271 msi_free( $2 );
273 | COND_AMPER identifier
275 COND_input* cond = (COND_input*) info;
276 INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
278 MSI_GetFeatureStateW(cond->package, $2, &install, &action );
279 $$ = action;
280 msi_free( $2 );
282 | COND_EXCLAM identifier
284 COND_input* cond = (COND_input*) info;
285 INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
287 MSI_GetFeatureStateW(cond->package, $2, &install, &action );
288 $$ = install;
289 msi_free( $2 );
293 symbol_s:
294 identifier
296 COND_input* cond = (COND_input*) info;
298 $$ = msi_dup_property( cond->package, $1 );
299 msi_free( $1 );
301 | COND_PERCENT identifier
303 UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
304 $$ = NULL;
305 if (len++)
307 $$ = msi_alloc( len*sizeof (WCHAR) );
308 GetEnvironmentVariableW( $2, $$, len );
310 msi_free( $2 );
314 identifier:
315 COND_IDENT
317 $$ = COND_GetString(&$1);
318 if( !$$ )
319 YYABORT;
323 integer:
324 COND_NUMBER
326 LPWSTR szNum = COND_GetString(&$1);
327 if( !szNum )
328 YYABORT;
329 $$ = atoiW( szNum );
330 msi_free( szNum );
337 static int COND_IsAlpha( WCHAR x )
339 return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) ||
340 ( ( x >= 'a' ) && ( x <= 'z' ) ) ||
341 ( ( x == '_' ) ) );
344 static int COND_IsNumber( WCHAR x )
346 return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') );
349 static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub )
351 LPWSTR strlower, sublower, r;
352 strlower = CharLowerW( strdupW( str ) );
353 sublower = CharLowerW( strdupW( sub ) );
354 r = strstrW( strlower, sublower );
355 if (r)
356 r = (LPWSTR)str + (r - strlower);
357 msi_free( strlower );
358 msi_free( sublower );
359 return r;
362 static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b )
364 /* null and empty string are equivalent */
365 if (!a) a = szEmpty;
366 if (!b) b = szEmpty;
368 /* a or b may be NULL */
369 switch (operator)
371 case COND_LT:
372 return -1 == lstrcmpW( a, b );
373 case COND_GT:
374 return 1 == lstrcmpW( a, b );
375 case COND_EQ:
376 return 0 == lstrcmpW( a, b );
377 case COND_NE:
378 return 0 != lstrcmpW( a, b );
379 case COND_GE:
380 return -1 != lstrcmpW( a, b );
381 case COND_LE:
382 return 1 != lstrcmpW( a, b );
383 case COND_SS: /* substring */
384 return strstrW( a, b ) ? 1 : 0;
385 case COND_ILT:
386 return -1 == lstrcmpiW( a, b );
387 case COND_IGT:
388 return 1 == lstrcmpiW( a, b );
389 case COND_IEQ:
390 return 0 == lstrcmpiW( a, b );
391 case COND_INE:
392 return 0 != lstrcmpiW( a, b );
393 case COND_IGE:
394 return -1 != lstrcmpiW( a, b );
395 case COND_ILE:
396 return 1 != lstrcmpiW( a, b );
397 case COND_ISS:
398 return strstriW( a, b ) ? 1 : 0;
399 case COND_LHS:
400 case COND_RHS:
401 case COND_ILHS:
402 case COND_IRHS:
403 ERR("unimplemented string comparison\n");
404 break;
405 default:
406 ERR("invalid integer operator\n");
407 return 0;
409 return 0;
413 static INT compare_int( INT a, INT operator, INT b )
415 switch (operator)
417 case COND_LT:
418 case COND_ILT:
419 return a < b;
420 case COND_GT:
421 case COND_IGT:
422 return a > b;
423 case COND_EQ:
424 case COND_IEQ:
425 return a == b;
426 case COND_NE:
427 case COND_INE:
428 return a != b;
429 case COND_GE:
430 case COND_IGE:
431 return a >= b;
432 case COND_LE:
433 case COND_ILE:
434 return a >= b;
435 case COND_SS:
436 case COND_ISS:
437 return ( a & b ) ? 1 : 0;
438 case COND_RHS:
439 return ( ( a & 0xffff ) == b ) ? 1 : 0;
440 case COND_LHS:
441 return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0;
442 default:
443 ERR("invalid integer operator\n");
444 return 0;
446 return 0;
450 static int COND_IsIdent( WCHAR x )
452 return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' )
453 || ( x == '#' ) || (x == '.') );
456 static int COND_GetOperator( COND_input *cond )
458 static const struct {
459 const WCHAR str[4];
460 int id;
461 } table[] = {
462 { {'~','=',0}, COND_IEQ },
463 { {'~','>','=',0}, COND_ILE },
464 { {'~','>','<',0}, COND_ISS },
465 { {'~','>','>',0}, COND_IRHS },
466 { {'~','>',0}, COND_ILT },
467 { {'~','<','>',0}, COND_INE },
468 { {'~','<','=',0}, COND_IGE },
469 { {'~','<','<',0}, COND_ILHS },
470 { {'~','<',0}, COND_IGT },
471 { {'>','=',0}, COND_GE },
472 { {'>','<',0}, COND_SS },
473 { {'>','>',0}, COND_LHS },
474 { {'>',0}, COND_GT },
475 { {'<','>',0}, COND_NE },
476 { {'<','=',0}, COND_LE },
477 { {'<','<',0}, COND_RHS },
478 { {'<',0}, COND_LT },
479 { {0}, 0 }
481 LPCWSTR p = &cond->str[cond->n];
482 int i = 0, len;
484 while ( 1 )
486 len = lstrlenW( table[i].str );
487 if ( !len || 0 == strncmpW( table[i].str, p, len ) )
488 break;
489 i++;
491 cond->n += len;
492 return table[i].id;
495 static int COND_GetOne( struct cond_str *str, COND_input *cond )
497 int rc, len = 1;
498 WCHAR ch;
500 str->data = &cond->str[cond->n];
502 ch = str->data[0];
504 switch( ch )
506 case 0: return 0;
507 case '(': rc = COND_LPAR; break;
508 case ')': rc = COND_RPAR; break;
509 case '&': rc = COND_AMPER; break;
510 case '!': rc = COND_EXCLAM; break;
511 case '$': rc = COND_DOLLARS; break;
512 case '?': rc = COND_QUESTION; break;
513 case '%': rc = COND_PERCENT; break;
514 case ' ': rc = COND_SPACE; break;
515 case '=': rc = COND_EQ; break;
516 break;
518 case '~':
519 case '<':
520 case '>':
521 rc = COND_GetOperator( cond );
522 if (!rc)
523 rc = COND_ERROR;
524 return rc;
525 default:
526 rc = 0;
529 if ( rc )
531 cond->n += len;
532 return rc;
535 if (ch == '"' )
537 LPCWSTR p = strchrW( str->data + 1, '"' );
538 if (!p)
539 return COND_ERROR;
540 len = p - str->data + 1;
541 rc = COND_LITER;
543 else if( COND_IsAlpha( ch ) )
545 static const WCHAR szNot[] = {'N','O','T',0};
546 static const WCHAR szAnd[] = {'A','N','D',0};
547 static const WCHAR szXor[] = {'X','O','R',0};
548 static const WCHAR szEqv[] = {'E','Q','V',0};
549 static const WCHAR szImp[] = {'I','M','P',0};
550 static const WCHAR szOr[] = {'O','R',0};
552 while( COND_IsIdent( str->data[len] ) )
553 len++;
554 rc = COND_IDENT;
556 if ( len == 3 )
558 if ( !strncmpiW( str->data, szNot, len ) )
559 rc = COND_NOT;
560 else if( !strncmpiW( str->data, szAnd, len ) )
561 rc = COND_AND;
562 else if( !strncmpiW( str->data, szXor, len ) )
563 rc = COND_XOR;
564 else if( !strncmpiW( str->data, szEqv, len ) )
565 rc = COND_EQV;
566 else if( !strncmpiW( str->data, szImp, len ) )
567 rc = COND_IMP;
569 else if( (len == 2) && !strncmpiW( str->data, szOr, len ) )
570 rc = COND_OR;
572 else if( COND_IsNumber( ch ) )
574 while( COND_IsNumber( str->data[len] ) )
575 len++;
576 rc = COND_NUMBER;
578 else
580 ERR("Got unknown character %c(%x)\n",ch,ch);
581 return COND_ERROR;
584 cond->n += len;
585 str->len = len;
587 return rc;
590 static int COND_lex( void *COND_lval, COND_input *cond )
592 int rc;
593 struct cond_str *str = COND_lval;
595 do {
596 rc = COND_GetOne( str, cond );
597 } while (rc == COND_SPACE);
599 return rc;
602 static LPWSTR COND_GetString( struct cond_str *str )
604 LPWSTR ret;
606 ret = msi_alloc( (str->len+1) * sizeof (WCHAR) );
607 if( ret )
609 memcpy( ret, str->data, str->len * sizeof(WCHAR));
610 ret[str->len]=0;
612 TRACE("Got identifier %s\n",debugstr_w(ret));
613 return ret;
616 static LPWSTR COND_GetLiteral( struct cond_str *str )
618 LPWSTR ret;
620 ret = msi_alloc( (str->len-1) * sizeof (WCHAR) );
621 if( ret )
623 memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) );
624 ret[str->len - 2]=0;
626 TRACE("Got literal %s\n",debugstr_w(ret));
627 return ret;
630 static int COND_error(const char *str)
632 TRACE("%s\n", str );
633 return 0;
636 MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
638 COND_input cond;
639 MSICONDITION r;
641 TRACE("%s\n", debugstr_w( szCondition ) );
643 if ( szCondition == NULL )
644 return MSICONDITION_NONE;
646 cond.package = package;
647 cond.str = szCondition;
648 cond.n = 0;
649 cond.result = MSICONDITION_ERROR;
651 if ( !COND_parse( &cond ) )
652 r = cond.result;
653 else
654 r = MSICONDITION_ERROR;
656 TRACE("%i <- %s\n", r, debugstr_w(szCondition));
657 return r;
660 MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition )
662 MSIPACKAGE *package;
663 UINT ret;
665 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
666 if( !package)
667 return MSICONDITION_ERROR;
668 ret = MSI_EvaluateConditionW( package, szCondition );
669 msiobj_release( &package->hdr );
670 return ret;
673 MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition )
675 LPWSTR szwCond = NULL;
676 MSICONDITION r;
678 szwCond = strdupAtoW( szCondition );
679 if( szCondition && !szwCond )
680 return MSICONDITION_ERROR;
682 r = MsiEvaluateConditionW( hInstall, szwCond );
683 msi_free( szwCond );
684 return r;