mciqtz: Improve MCIQTZ_mciSet traces.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #define COBJMACROS
24
25 #include "config.h"
26
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "msi.h"
35 #include "msiquery.h"
36 #include "objbase.h"
37 #include "oleauto.h"
38
39 #include "msipriv.h"
40 #include "msiserver.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43
44 #define YYLEX_PARAM info
45 #define YYPARSE_PARAM info
46
47 static int cond_error(const char *str);
48
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
50
51 typedef struct tag_yyinput
52 {
53     MSIPACKAGE *package;
54     LPCWSTR str;
55     INT    n;
56     MSICONDITION result;
57 } COND_input;
58
59 struct cond_str {
60     LPCWSTR data;
61     INT len;
62 };
63
64 static LPWSTR COND_GetString( const struct cond_str *str );
65 static LPWSTR COND_GetLiteral( const struct cond_str *str );
66 static int cond_lex( void *COND_lval, COND_input *info);
67
68 static INT compare_int( INT a, INT operator, INT b );
69 static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert );
70
71 static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b, BOOL convert )
72 {
73     INT r;
74
75     r = compare_string( a, op, b, convert );
76     msi_free( a );
77     msi_free( b );
78     return r;
79 }
80
81 static BOOL num_from_prop( LPCWSTR p, INT *val )
82 {
83     INT ret = 0, sign = 1;
84
85     if (!p)
86         return FALSE;
87     if (*p == '-')
88     {
89         sign = -1;
90         p++;
91     }
92     if (!*p)
93         return FALSE;
94     while (*p)
95     {
96         if( *p < '0' || *p > '9' )
97             return FALSE;
98         ret = ret*10 + (*p - '0');
99         p++;
100     }
101     *val = ret*sign;
102     return TRUE;
103 }
104
105 %}
106
107 %pure-parser
108
109 %union
110 {
111     struct cond_str str;
112     LPWSTR    string;
113     INT       value;
114 }
115
116 %token COND_SPACE COND_EOF
117 %token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV
118 %token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE
119 %token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE
120 %token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS
121 %token COND_ILHS COND_IRHS COND_LHS COND_RHS
122 %token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
123 %token <str> COND_IDENT <str> COND_NUMBER <str> COND_LITER
124
125 %nonassoc COND_ERROR COND_EOF
126
127 %type <value> expression boolean_term boolean_factor 
128 %type <value> value_i integer operator
129 %type <string> identifier symbol_s value_s literal
130
131 %%
132
133 condition:
134     expression 
135         {
136             COND_input* cond = (COND_input*) info;
137             cond->result = $1;
138         }
139   | /* empty */
140         {
141             COND_input* cond = (COND_input*) info;
142             cond->result = MSICONDITION_NONE;
143         }
144     ;
145
146 expression:
147     boolean_term 
148         {
149             $$ = $1;
150         }
151   | expression COND_OR boolean_term
152         {
153             $$ = $1 || $3;
154         }
155   | expression COND_IMP boolean_term
156         {
157             $$ = !$1 || $3;
158         }
159   | expression COND_XOR boolean_term
160         {
161             $$ = ( $1 || $3 ) && !( $1 && $3 );
162         }
163   | expression COND_EQV boolean_term
164         {
165             $$ = ( $1 && $3 ) || ( !$1 && !$3 );
166         }
167     ;
168
169 boolean_term:
170     boolean_factor
171         {
172             $$ = $1;
173         }
174   | boolean_term COND_AND boolean_factor
175         {
176             $$ = $1 && $3;
177         }
178     ;
179
180 boolean_factor:
181     COND_NOT boolean_factor
182         {
183             $$ = $2 ? 0 : 1;
184         }
185   | value_i
186         {
187             $$ = $1 ? 1 : 0;
188         }
189   | value_s
190         {
191             $$ = ($1 && $1[0]) ? 1 : 0;
192             msi_free($1);
193         }
194   | value_i operator value_i
195         {
196             $$ = compare_int( $1, $2, $3 );
197         }
198   | symbol_s operator value_i
199         {
200             int num;
201             if (num_from_prop( $1, &num ))
202                 $$ = compare_int( num, $2, $3 );
203             else 
204                 $$ = ($2 == COND_NE || $2 == COND_INE );
205             msi_free($1);
206         }
207   | value_i operator symbol_s
208         {
209             int num;
210             if (num_from_prop( $3, &num ))
211                 $$ = compare_int( $1, $2, num );
212             else 
213                 $$ = ($2 == COND_NE || $2 == COND_INE );
214             msi_free($3);
215         }
216   | symbol_s operator symbol_s
217         {
218             $$ = compare_and_free_strings( $1, $2, $3, TRUE );
219         }
220   | symbol_s operator literal
221         {
222             $$ = compare_and_free_strings( $1, $2, $3, TRUE );
223         }
224   | literal operator symbol_s
225         {
226             $$ = compare_and_free_strings( $1, $2, $3, TRUE );
227         }
228   | literal operator literal
229         {
230             $$ = compare_and_free_strings( $1, $2, $3, FALSE );
231         }
232   | literal operator value_i
233         {
234             $$ = 0;
235             msi_free($1);
236         }
237   | value_i operator literal
238         {
239             $$ = 0;
240             msi_free($3);
241         }
242   | COND_LPAR expression COND_RPAR
243         {
244             $$ = $2;
245         }
246     ;
247
248 operator:
249     /* common functions */
250     COND_EQ { $$ = COND_EQ; }
251   | COND_NE { $$ = COND_NE; }
252   | COND_LT { $$ = COND_LT; }
253   | COND_GT { $$ = COND_GT; }
254   | COND_LE { $$ = COND_LE; }
255   | COND_GE { $$ = COND_GE; }
256   | COND_SS { $$ = COND_SS; }
257   | COND_IEQ { $$ = COND_IEQ; }
258   | COND_INE { $$ = COND_INE; }
259   | COND_ILT { $$ = COND_ILT; }
260   | COND_IGT { $$ = COND_IGT; }
261   | COND_ILE { $$ = COND_ILE; }
262   | COND_IGE { $$ = COND_IGE; }
263   | COND_ISS { $$ = COND_ISS; }
264   | COND_LHS { $$ = COND_LHS; }
265   | COND_RHS { $$ = COND_RHS; }
266   | COND_ILHS { $$ = COND_ILHS; }
267   | COND_IRHS { $$ = COND_IRHS; }
268     ;
269
270 value_s:
271     symbol_s
272     {
273         $$ = $1;
274     } 
275   | literal
276     {
277         $$ = $1;
278     }
279     ;
280
281 literal:
282     COND_LITER
283         {
284             $$ = COND_GetLiteral(&$1);
285             if( !$$ )
286                 YYABORT;
287         }
288     ;
289
290 value_i:
291     integer
292         {
293             $$ = $1;
294         }
295   | COND_DOLLARS identifier
296         {
297             COND_input* cond = (COND_input*) info;
298             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
299       
300             MSI_GetComponentStateW(cond->package, $2, &install, &action );
301             $$ = action;
302             msi_free( $2 );
303         }
304   | COND_QUESTION identifier
305         {
306             COND_input* cond = (COND_input*) info;
307             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
308       
309             MSI_GetComponentStateW(cond->package, $2, &install, &action );
310             $$ = install;
311             msi_free( $2 );
312         }
313   | COND_AMPER identifier
314         {
315             COND_input* cond = (COND_input*) info;
316             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
317       
318             MSI_GetFeatureStateW(cond->package, $2, &install, &action );
319             if (action == INSTALLSTATE_UNKNOWN)
320                 $$ = MSICONDITION_FALSE;
321             else
322                 $$ = action;
323
324             msi_free( $2 );
325         }
326   | COND_EXCLAM identifier
327         {
328             COND_input* cond = (COND_input*) info;
329             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
330       
331             MSI_GetFeatureStateW(cond->package, $2, &install, &action );
332             $$ = install;
333             msi_free( $2 );
334         }
335     ;
336
337 symbol_s:
338     identifier
339         {
340             COND_input* cond = (COND_input*) info;
341
342             $$ = msi_dup_property( cond->package, $1 );
343             msi_free( $1 );
344         }
345     | COND_PERCENT identifier
346         {
347             UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
348             $$ = NULL;
349             if (len++)
350             {
351                 $$ = msi_alloc( len*sizeof (WCHAR) );
352                 GetEnvironmentVariableW( $2, $$, len );
353             }
354             msi_free( $2 );
355         }
356     ;
357
358 identifier:
359     COND_IDENT
360         {
361             $$ = COND_GetString(&$1);
362             if( !$$ )
363                 YYABORT;
364         }
365     ;
366
367 integer:
368     COND_NUMBER
369         {
370             LPWSTR szNum = COND_GetString(&$1);
371             if( !szNum )
372                 YYABORT;
373             $$ = atoiW( szNum );
374             msi_free( szNum );
375         }
376     ;
377
378 %%
379
380
381 static int COND_IsAlpha( WCHAR x )
382 {
383     return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) ||
384             ( ( x >= 'a' ) && ( x <= 'z' ) ) ||
385             ( ( x == '_' ) ) );
386 }
387
388 static int COND_IsNumber( WCHAR x )
389 {
390     return( (( x >= '0' ) && ( x <= '9' ))  || (x =='-') || (x =='.') );
391 }
392
393 static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub )
394 {
395     LPWSTR strlower, sublower, r;
396     strlower = CharLowerW( strdupW( str ) );
397     sublower = CharLowerW( strdupW( sub ) );
398     r = strstrW( strlower, sublower );
399     if (r)
400         r = (LPWSTR)str + (r - strlower);
401     msi_free( strlower );
402     msi_free( sublower );
403     return r;
404 }
405
406 static BOOL str_is_number( LPCWSTR str )
407 {
408     int i;
409
410     if (!*str)
411         return FALSE;
412
413     for (i = 0; i < lstrlenW( str ); i++)
414         if (!isdigitW(str[i]))
415             return FALSE;
416
417     return TRUE;
418 }
419
420 static INT compare_substring( LPCWSTR a, INT operator, LPCWSTR b )
421 {
422     int lhs, rhs;
423
424     /* substring operators return 0 if LHS is missing */
425     if (!a || !*a)
426         return 0;
427
428     /* substring operators return 1 if RHS is missing */
429     if (!b || !*b)
430         return 1;
431
432     /* if both strings contain only numbers, use integer comparison */
433     lhs = atoiW(a);
434     rhs = atoiW(b);
435     if (str_is_number(a) && str_is_number(b))
436         return compare_int( lhs, operator, rhs );
437
438     switch (operator)
439     {
440     case COND_SS:
441         return strstrW( a, b ) ? 1 : 0;
442     case COND_ISS:
443         return strstriW( a, b ) ? 1 : 0;
444     case COND_LHS:
445         return 0 == strncmpW( a, b, lstrlenW( b ) );
446     case COND_RHS:
447         return 0 == lstrcmpW( a + (lstrlenW( a ) - lstrlenW( b )), b );
448     case COND_ILHS:
449         return 0 == strncmpiW( a, b, lstrlenW( b ) );
450     case COND_IRHS:
451         return 0 == lstrcmpiW( a + (lstrlenW( a ) - lstrlenW( b )), b );
452     default:
453         ERR("invalid substring operator\n");
454         return 0;
455     }
456     return 0;
457 }
458
459 static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert )
460 {
461     if (operator >= COND_SS && operator <= COND_RHS)
462         return compare_substring( a, operator, b );
463         
464     /* null and empty string are equivalent */
465     if (!a) a = szEmpty;
466     if (!b) b = szEmpty;
467
468     if (convert && str_is_number(a) && str_is_number(b))
469         return compare_int( atoiW(a), operator, atoiW(b) );
470
471     /* a or b may be NULL */
472     switch (operator)
473     {
474     case COND_LT:
475         return -1 == lstrcmpW( a, b );
476     case COND_GT:
477         return  1 == lstrcmpW( a, b );
478     case COND_EQ:
479         return  0 == lstrcmpW( a, b );
480     case COND_NE:
481         return  0 != lstrcmpW( a, b );
482     case COND_GE:
483         return -1 != lstrcmpW( a, b );
484     case COND_LE:
485         return  1 != lstrcmpW( a, b );
486     case COND_ILT:
487         return -1 == lstrcmpiW( a, b );
488     case COND_IGT:
489         return  1 == lstrcmpiW( a, b );
490     case COND_IEQ:
491         return  0 == lstrcmpiW( a, b );
492     case COND_INE:
493         return  0 != lstrcmpiW( a, b );
494     case COND_IGE:
495         return -1 != lstrcmpiW( a, b );
496     case COND_ILE:
497         return  1 != lstrcmpiW( a, b );
498     default:
499         ERR("invalid string operator\n");
500         return 0;
501     }
502     return 0;
503 }
504
505
506 static INT compare_int( INT a, INT operator, INT b )
507 {
508     switch (operator)
509     {
510     case COND_LT:
511     case COND_ILT:
512         return a < b;
513     case COND_GT:
514     case COND_IGT:
515         return a > b;
516     case COND_EQ:
517     case COND_IEQ:
518         return a == b;
519     case COND_NE:
520     case COND_INE:
521         return a != b;
522     case COND_GE:
523     case COND_IGE:
524         return a >= b;
525     case COND_LE:
526     case COND_ILE:
527         return a <= b;
528     case COND_SS:
529     case COND_ISS:
530         return ( a & b ) ? 1 : 0;
531     case COND_RHS:
532         return ( ( a & 0xffff ) == b ) ? 1 : 0;
533     case COND_LHS:
534         return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0;
535     default:
536         ERR("invalid integer operator\n");
537         return 0;
538     }
539     return 0;
540 }
541
542
543 static int COND_IsIdent( WCHAR x )
544 {
545     return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) 
546             || ( x == '#' ) || (x == '.') );
547 }
548
549 static int COND_GetOperator( COND_input *cond )
550 {
551     static const struct {
552         const WCHAR str[4];
553         int id;
554     } table[] = {
555         { {'~','<','=',0}, COND_ILE },
556         { {'~','>','<',0}, COND_ISS },
557         { {'~','>','>',0}, COND_IRHS },
558         { {'~','<','>',0}, COND_INE },
559         { {'~','>','=',0}, COND_IGE },
560         { {'~','<','<',0}, COND_ILHS },
561         { {'~','=',0},     COND_IEQ },
562         { {'~','<',0},     COND_ILT },
563         { {'~','>',0},     COND_IGT },
564         { {'>','=',0},     COND_GE  },
565         { {'>','<',0},     COND_SS  },
566         { {'<','<',0},     COND_LHS },
567         { {'<','>',0},     COND_NE  },
568         { {'<','=',0},     COND_LE  },
569         { {'>','>',0},     COND_RHS },
570         { {'>',0},         COND_GT  },
571         { {'<',0},         COND_LT  },
572         { {0},             0        }
573     };
574     LPCWSTR p = &cond->str[cond->n];
575     int i = 0, len;
576
577     while ( 1 )
578     {
579         len = lstrlenW( table[i].str );
580         if ( !len || 0 == strncmpW( table[i].str, p, len ) )
581             break;
582         i++;
583     }
584     cond->n += len;
585     return table[i].id;
586 }
587
588 static int COND_GetOne( struct cond_str *str, COND_input *cond )
589 {
590     int rc, len = 1;
591     WCHAR ch;
592
593     str->data = &cond->str[cond->n];
594
595     ch = str->data[0];
596
597     switch( ch )
598     {
599     case 0: return 0;
600     case '(': rc = COND_LPAR; break;
601     case ')': rc = COND_RPAR; break;
602     case '&': rc = COND_AMPER; break;
603     case '!': rc = COND_EXCLAM; break;
604     case '$': rc = COND_DOLLARS; break;
605     case '?': rc = COND_QUESTION; break;
606     case '%': rc = COND_PERCENT; break;
607     case ' ': rc = COND_SPACE; break;
608     case '=': rc = COND_EQ; break;
609
610     case '~':
611     case '<':
612     case '>':
613         rc = COND_GetOperator( cond );
614         if (!rc)
615             rc = COND_ERROR;
616         return rc;
617     default:
618         rc = 0;
619     }
620
621     if ( rc )
622     {
623         cond->n += len;
624         return rc;
625     }
626
627     if (ch == '"' )
628     {
629         LPCWSTR p = strchrW( str->data + 1, '"' );
630         if (!p)
631             return COND_ERROR;
632         len = p - str->data + 1;
633         rc = COND_LITER;
634     }
635     else if( COND_IsAlpha( ch ) )
636     {
637         static const WCHAR szNot[] = {'N','O','T',0};
638         static const WCHAR szAnd[] = {'A','N','D',0};
639         static const WCHAR szXor[] = {'X','O','R',0};
640         static const WCHAR szEqv[] = {'E','Q','V',0};
641         static const WCHAR szImp[] = {'I','M','P',0};
642         static const WCHAR szOr[] = {'O','R',0};
643
644         while( COND_IsIdent( str->data[len] ) )
645             len++;
646         rc = COND_IDENT;
647
648         if ( len == 3 )
649         {
650             if ( !strncmpiW( str->data, szNot, len ) )
651                 rc = COND_NOT;
652             else if( !strncmpiW( str->data, szAnd, len ) )
653                 rc = COND_AND;
654             else if( !strncmpiW( str->data, szXor, len ) )
655                 rc = COND_XOR;
656             else if( !strncmpiW( str->data, szEqv, len ) )
657                 rc = COND_EQV;
658             else if( !strncmpiW( str->data, szImp, len ) )
659                 rc = COND_IMP;
660         }
661         else if( (len == 2) && !strncmpiW( str->data, szOr, len ) )
662             rc = COND_OR;
663     }
664     else if( COND_IsNumber( ch ) )
665     {
666         while( COND_IsNumber( str->data[len] ) )
667             len++;
668         rc = COND_NUMBER;
669     }
670     else
671     {
672         ERR("Got unknown character %c(%x)\n",ch,ch);
673         return COND_ERROR;
674     }
675
676     cond->n += len;
677     str->len = len;
678
679     return rc;
680 }
681
682 static int cond_lex( void *COND_lval, COND_input *cond )
683 {
684     int rc;
685     struct cond_str *str = COND_lval;
686
687     do {
688         rc = COND_GetOne( str, cond );
689     } while (rc == COND_SPACE);
690     
691     return rc;
692 }
693
694 static LPWSTR COND_GetString( const struct cond_str *str )
695 {
696     LPWSTR ret;
697
698     ret = msi_alloc( (str->len+1) * sizeof (WCHAR) );
699     if( ret )
700     {
701         memcpy( ret, str->data, str->len * sizeof(WCHAR));
702         ret[str->len]=0;
703     }
704     TRACE("Got identifier %s\n",debugstr_w(ret));
705     return ret;
706 }
707
708 static LPWSTR COND_GetLiteral( const struct cond_str *str )
709 {
710     LPWSTR ret;
711
712     ret = msi_alloc( (str->len-1) * sizeof (WCHAR) );
713     if( ret )
714     {
715         memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) );
716         ret[str->len - 2]=0;
717     }
718     TRACE("Got literal %s\n",debugstr_w(ret));
719     return ret;
720 }
721
722 static int cond_error(const char *str)
723 {
724     TRACE("%s\n", str );
725     return 0;
726 }
727
728 MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
729 {
730     COND_input cond;
731     MSICONDITION r;
732
733     TRACE("%s\n", debugstr_w( szCondition ) );
734
735     if ( szCondition == NULL )
736         return MSICONDITION_NONE;
737
738     cond.package = package;
739     cond.str   = szCondition;
740     cond.n     = 0;
741     cond.result = MSICONDITION_ERROR;
742     
743     if ( !cond_parse( &cond ) )
744         r = cond.result;
745     else
746         r = MSICONDITION_ERROR;
747
748     TRACE("%i <- %s\n", r, debugstr_w(szCondition));
749     return r;
750 }
751
752 MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition )
753 {
754     MSIPACKAGE *package;
755     UINT ret;
756
757     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
758     if( !package )
759     {
760         HRESULT hr;
761         BSTR condition;
762         IWineMsiRemotePackage *remote_package;
763
764         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
765         if (!remote_package)
766             return MSICONDITION_ERROR;
767
768         condition = SysAllocString( szCondition );
769         if (!condition)
770         {
771             IWineMsiRemotePackage_Release( remote_package );
772             return ERROR_OUTOFMEMORY;
773         }
774
775         hr = IWineMsiRemotePackage_EvaluateCondition( remote_package, condition );
776
777         SysFreeString( condition );
778         IWineMsiRemotePackage_Release( remote_package );
779
780         if (FAILED(hr))
781         {
782             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
783                 return HRESULT_CODE(hr);
784
785             return ERROR_FUNCTION_FAILED;
786         }
787
788         return ERROR_SUCCESS;
789     }
790
791     ret = MSI_EvaluateConditionW( package, szCondition );
792     msiobj_release( &package->hdr );
793     return ret;
794 }
795
796 MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition )
797 {
798     LPWSTR szwCond = NULL;
799     MSICONDITION r;
800
801     szwCond = strdupAtoW( szCondition );
802     if( szCondition && !szwCond )
803         return MSICONDITION_ERROR;
804
805     r = MsiEvaluateConditionW( hInstall, szwCond );
806     msi_free( szwCond );
807     return r;
808 }