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