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