msi: Use the initial dialog position values in the database when creating the dialog...
[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 INT compare_string( LPCWSTR a, INT operator, LPCWSTR b )
400 {
401     /* null and empty string are equivalent */
402     if (!a) a = szEmpty;
403     if (!b) b = szEmpty;
404
405     /* a or b may be NULL */
406     switch (operator)
407     {
408     case COND_LT:
409         return -1 == lstrcmpW( a, b );
410     case COND_GT:
411         return  1 == lstrcmpW( a, b );
412     case COND_EQ:
413         return  0 == lstrcmpW( a, b );
414     case COND_NE:
415         return  0 != lstrcmpW( a, b );
416     case COND_GE:
417         return -1 != lstrcmpW( a, b );
418     case COND_LE:
419         return  1 != lstrcmpW( a, b );
420     case COND_SS: /* substring */
421         return strstrW( a, b ) ? 1 : 0;
422     case COND_ILT:
423         return -1 == lstrcmpiW( a, b );
424     case COND_IGT:
425         return  1 == lstrcmpiW( a, b );
426     case COND_IEQ:
427         return  0 == lstrcmpiW( a, b );
428     case COND_INE:
429         return  0 != lstrcmpiW( a, b );
430     case COND_IGE:
431         return -1 != lstrcmpiW( a, b );
432     case COND_ILE:
433         return  1 != lstrcmpiW( a, b );
434     case COND_ISS:
435         return strstriW( a, b ) ? 1 : 0;
436     case COND_LHS:
437     case COND_RHS:
438     case COND_ILHS:
439     case COND_IRHS:
440         ERR("unimplemented string comparison\n");
441         break;
442     default:
443         ERR("invalid integer operator\n");
444         return 0;
445     }
446     return 0;
447 }
448
449
450 static INT compare_int( INT a, INT operator, INT b )
451 {
452     switch (operator)
453     {
454     case COND_LT:
455     case COND_ILT:
456         return a < b;
457     case COND_GT:
458     case COND_IGT:
459         return a > b;
460     case COND_EQ:
461     case COND_IEQ:
462         return a == b;
463     case COND_NE:
464     case COND_INE:
465         return a != b;
466     case COND_GE:
467     case COND_IGE:
468         return a >= b;
469     case COND_LE:
470     case COND_ILE:
471         return a <= b;
472     case COND_SS:
473     case COND_ISS:
474         return ( a & b ) ? 1 : 0;
475     case COND_RHS:
476         return ( ( a & 0xffff ) == b ) ? 1 : 0;
477     case COND_LHS:
478         return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0;
479     default:
480         ERR("invalid integer operator\n");
481         return 0;
482     }
483     return 0;
484 }
485
486
487 static int COND_IsIdent( WCHAR x )
488 {
489     return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) 
490             || ( x == '#' ) || (x == '.') );
491 }
492
493 static int COND_GetOperator( COND_input *cond )
494 {
495     static const struct {
496         const WCHAR str[4];
497         int id;
498     } table[] = {
499         { {'~','=',0},     COND_IEQ },
500         { {'~','<','=',0}, COND_ILE },
501         { {'~','>','<',0}, COND_ISS },
502         { {'~','>','>',0}, COND_IRHS },
503         { {'~','<','>',0}, COND_INE },
504         { {'~','<',0},     COND_ILT },
505         { {'~','>','=',0}, COND_IGE },
506         { {'~','<','<',0}, COND_ILHS },
507         { {'~','>',0},     COND_IGT },
508         { {'>','=',0},     COND_GE  },
509         { {'>','<',0},     COND_SS  },
510         { {'<','<',0},     COND_LHS },
511         { {'>',0},         COND_GT  },
512         { {'<','>',0},     COND_NE  },
513         { {'<','=',0},     COND_LE  },
514         { {'>','>',0},     COND_RHS },
515         { {'<',0},         COND_LT  },
516         { {0},             0        }
517     };
518     LPCWSTR p = &cond->str[cond->n];
519     int i = 0, len;
520
521     while ( 1 )
522     {
523         len = lstrlenW( table[i].str );
524         if ( !len || 0 == strncmpW( table[i].str, p, len ) )
525             break;
526         i++;
527     }
528     cond->n += len;
529     return table[i].id;
530 }
531
532 static int COND_GetOne( struct cond_str *str, COND_input *cond )
533 {
534     int rc, len = 1;
535     WCHAR ch;
536
537     str->data = &cond->str[cond->n];
538
539     ch = str->data[0];
540
541     switch( ch )
542     {
543     case 0: return 0;
544     case '(': rc = COND_LPAR; break;
545     case ')': rc = COND_RPAR; break;
546     case '&': rc = COND_AMPER; break;
547     case '!': rc = COND_EXCLAM; break;
548     case '$': rc = COND_DOLLARS; break;
549     case '?': rc = COND_QUESTION; break;
550     case '%': rc = COND_PERCENT; break;
551     case ' ': rc = COND_SPACE; break;
552     case '=': rc = COND_EQ; break;
553         break;
554
555     case '~':
556     case '<':
557     case '>':
558         rc = COND_GetOperator( cond );
559         if (!rc)
560             rc = COND_ERROR;
561         return rc;
562     default:
563         rc = 0;
564     }
565
566     if ( rc )
567     {
568         cond->n += len;
569         return rc;
570     }
571
572     if (ch == '"' )
573     {
574         LPCWSTR p = strchrW( str->data + 1, '"' );
575         if (!p)
576             return COND_ERROR;
577         len = p - str->data + 1;
578         rc = COND_LITER;
579     }
580     else if( COND_IsAlpha( ch ) )
581     {
582         static const WCHAR szNot[] = {'N','O','T',0};
583         static const WCHAR szAnd[] = {'A','N','D',0};
584         static const WCHAR szXor[] = {'X','O','R',0};
585         static const WCHAR szEqv[] = {'E','Q','V',0};
586         static const WCHAR szImp[] = {'I','M','P',0};
587         static const WCHAR szOr[] = {'O','R',0};
588
589         while( COND_IsIdent( str->data[len] ) )
590             len++;
591         rc = COND_IDENT;
592
593         if ( len == 3 )
594         {
595             if ( !strncmpiW( str->data, szNot, len ) )
596                 rc = COND_NOT;
597             else if( !strncmpiW( str->data, szAnd, len ) )
598                 rc = COND_AND;
599             else if( !strncmpiW( str->data, szXor, len ) )
600                 rc = COND_XOR;
601             else if( !strncmpiW( str->data, szEqv, len ) )
602                 rc = COND_EQV;
603             else if( !strncmpiW( str->data, szImp, len ) )
604                 rc = COND_IMP;
605         }
606         else if( (len == 2) && !strncmpiW( str->data, szOr, len ) )
607             rc = COND_OR;
608     }
609     else if( COND_IsNumber( ch ) )
610     {
611         while( COND_IsNumber( str->data[len] ) )
612             len++;
613         rc = COND_NUMBER;
614     }
615     else
616     {
617         ERR("Got unknown character %c(%x)\n",ch,ch);
618         return COND_ERROR;
619     }
620
621     cond->n += len;
622     str->len = len;
623
624     return rc;
625 }
626
627 static int COND_lex( void *COND_lval, COND_input *cond )
628 {
629     int rc;
630     struct cond_str *str = COND_lval;
631
632     do {
633         rc = COND_GetOne( str, cond );
634     } while (rc == COND_SPACE);
635     
636     return rc;
637 }
638
639 static LPWSTR COND_GetString( struct cond_str *str )
640 {
641     LPWSTR ret;
642
643     ret = msi_alloc( (str->len+1) * sizeof (WCHAR) );
644     if( ret )
645     {
646         memcpy( ret, str->data, str->len * sizeof(WCHAR));
647         ret[str->len]=0;
648     }
649     TRACE("Got identifier %s\n",debugstr_w(ret));
650     return ret;
651 }
652
653 static LPWSTR COND_GetLiteral( struct cond_str *str )
654 {
655     LPWSTR ret;
656
657     ret = msi_alloc( (str->len-1) * sizeof (WCHAR) );
658     if( ret )
659     {
660         memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) );
661         ret[str->len - 2]=0;
662     }
663     TRACE("Got literal %s\n",debugstr_w(ret));
664     return ret;
665 }
666
667 static int COND_error(const char *str)
668 {
669     TRACE("%s\n", str );
670     return 0;
671 }
672
673 MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
674 {
675     COND_input cond;
676     MSICONDITION r;
677
678     TRACE("%s\n", debugstr_w( szCondition ) );
679
680     if ( szCondition == NULL )
681         return MSICONDITION_NONE;
682
683     cond.package = package;
684     cond.str   = szCondition;
685     cond.n     = 0;
686     cond.result = MSICONDITION_ERROR;
687     
688     if ( !COND_parse( &cond ) )
689         r = cond.result;
690     else
691         r = MSICONDITION_ERROR;
692
693     TRACE("%i <- %s\n", r, debugstr_w(szCondition));
694     return r;
695 }
696
697 MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition )
698 {
699     MSIPACKAGE *package;
700     UINT ret;
701
702     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
703     if( !package)
704         return MSICONDITION_ERROR;
705     ret = MSI_EvaluateConditionW( package, szCondition );
706     msiobj_release( &package->hdr );
707     return ret;
708 }
709
710 MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition )
711 {
712     LPWSTR szwCond = NULL;
713     MSICONDITION r;
714
715     szwCond = strdupAtoW( szCondition );
716     if( szCondition && !szwCond )
717         return MSICONDITION_ERROR;
718
719     r = MsiEvaluateConditionW( hInstall, szwCond );
720     msi_free( szwCond );
721     return r;
722 }