Convert MsiEnumComponentQualifiers to use msi_strcpy_to_awstring.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 COND_SPACE
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         }
190   | value_i operator value_i
191         {
192             $$ = compare_int( $1, $2, $3 );
193         }
194   | symbol_s operator value_i
195         {
196             int num;
197             if (num_from_prop( $1, &num ))
198                 $$ = compare_int( num, $2, $3 );
199             else 
200                 $$ = ($2 == COND_NE || $2 == COND_INE );
201         }
202   | value_i operator symbol_s
203         {
204             int num;
205             if (num_from_prop( $3, &num ))
206                 $$ = compare_int( $1, $2, num );
207             else 
208                 $$ = ($2 == COND_NE || $2 == COND_INE );
209         }
210   | symbol_s operator symbol_s
211         {
212             $$ = compare_and_free_strings( $1, $2, $3 );
213         }
214   | symbol_s operator literal
215         {
216             $$ = compare_and_free_strings( $1, $2, $3 );
217         }
218   | literal operator symbol_s
219         {
220             $$ = compare_and_free_strings( $1, $2, $3 );
221         }
222   | literal operator literal
223         {
224             $$ = compare_and_free_strings( $1, $2, $3 );
225         }
226   | literal operator value_i
227         {
228             $$ = 0;
229         }
230   | value_i operator literal
231         {
232             $$ = 0;
233         }
234   | COND_LPAR expression COND_RPAR
235         {
236             $$ = $2;
237         }
238     ;
239
240 operator:
241     /* common functions */
242     COND_EQ { $$ = COND_EQ; }
243   | COND_NE { $$ = COND_NE; }
244   | COND_LT { $$ = COND_LT; }
245   | COND_GT { $$ = COND_GT; }
246   | COND_LE { $$ = COND_LE; }
247   | COND_GE { $$ = COND_GE; }
248   | COND_SS { $$ = COND_SS; }
249   | COND_IEQ { $$ = COND_IEQ; }
250   | COND_INE { $$ = COND_INE; }
251   | COND_ILT { $$ = COND_ILT; }
252   | COND_IGT { $$ = COND_IGT; }
253   | COND_ILE { $$ = COND_ILE; }
254   | COND_IGE { $$ = COND_IGE; }
255   | COND_ISS { $$ = COND_ISS; }
256   | COND_LHS { $$ = COND_LHS; }
257   | COND_RHS { $$ = COND_RHS; }
258   | COND_ILHS { $$ = COND_ILHS; }
259   | COND_IRHS { $$ = COND_IRHS; }
260     ;
261
262 value_s:
263     symbol_s
264     {
265         $$ = $1;
266     } 
267   | literal
268     {
269         $$ = $1;
270     }
271     ;
272
273 literal:
274     COND_LITER
275         {
276             $$ = COND_GetLiteral(&$1);
277             if( !$$ )
278                 YYABORT;
279         }
280     ;
281
282 value_i:
283     integer
284         {
285             $$ = $1;
286         }
287   | COND_DOLLARS identifier
288         {
289             COND_input* cond = (COND_input*) info;
290             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
291       
292             MSI_GetComponentStateW(cond->package, $2, &install, &action );
293             $$ = action;
294             msi_free( $2 );
295         }
296   | COND_QUESTION 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             $$ = install;
303             msi_free( $2 );
304         }
305   | COND_AMPER identifier
306         {
307             COND_input* cond = (COND_input*) info;
308             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
309       
310             MSI_GetFeatureStateW(cond->package, $2, &install, &action );
311             $$ = action;
312             msi_free( $2 );
313         }
314   | COND_EXCLAM 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             $$ = install;
321             msi_free( $2 );
322         }
323     ;
324
325 symbol_s:
326     identifier
327         {
328             COND_input* cond = (COND_input*) info;
329
330             $$ = msi_dup_property( cond->package, $1 );
331             msi_free( $1 );
332         }
333     | COND_PERCENT identifier
334         {
335             UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
336             $$ = NULL;
337             if (len++)
338             {
339                 $$ = msi_alloc( len*sizeof (WCHAR) );
340                 GetEnvironmentVariableW( $2, $$, len );
341             }
342             msi_free( $2 );
343         }
344     ;
345
346 identifier:
347     COND_IDENT
348         {
349             $$ = COND_GetString(&$1);
350             if( !$$ )
351                 YYABORT;
352         }
353     ;
354
355 integer:
356     COND_NUMBER
357         {
358             LPWSTR szNum = COND_GetString(&$1);
359             if( !szNum )
360                 YYABORT;
361             $$ = atoiW( szNum );
362             msi_free( szNum );
363         }
364     ;
365
366 %%
367
368
369 static int COND_IsAlpha( WCHAR x )
370 {
371     return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) ||
372             ( ( x >= 'a' ) && ( x <= 'z' ) ) ||
373             ( ( x == '_' ) ) );
374 }
375
376 static int COND_IsNumber( WCHAR x )
377 {
378     return( (( x >= '0' ) && ( x <= '9' ))  || (x =='-') || (x =='.') );
379 }
380
381 static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub )
382 {
383     LPWSTR strlower, sublower, r;
384     strlower = CharLowerW( strdupW( str ) );
385     sublower = CharLowerW( strdupW( sub ) );
386     r = strstrW( strlower, sublower );
387     if (r)
388         r = (LPWSTR)str + (r - strlower);
389     msi_free( strlower );
390     msi_free( sublower );
391     return r;
392 }
393
394 static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b )
395 {
396     /* null and empty string are equivalent */
397     if (!a) a = szEmpty;
398     if (!b) b = szEmpty;
399
400     /* a or b may be NULL */
401     switch (operator)
402     {
403     case COND_LT:
404         return -1 == lstrcmpW( a, b );
405     case COND_GT:
406         return  1 == lstrcmpW( a, b );
407     case COND_EQ:
408         return  0 == lstrcmpW( a, b );
409     case COND_NE:
410         return  0 != lstrcmpW( a, b );
411     case COND_GE:
412         return -1 != lstrcmpW( a, b );
413     case COND_LE:
414         return  1 != lstrcmpW( a, b );
415     case COND_SS: /* substring */
416         return strstrW( a, b ) ? 1 : 0;
417     case COND_ILT:
418         return -1 == lstrcmpiW( a, b );
419     case COND_IGT:
420         return  1 == lstrcmpiW( a, b );
421     case COND_IEQ:
422         return  0 == lstrcmpiW( a, b );
423     case COND_INE:
424         return  0 != lstrcmpiW( a, b );
425     case COND_IGE:
426         return -1 != lstrcmpiW( a, b );
427     case COND_ILE:
428         return  1 != lstrcmpiW( a, b );
429     case COND_ISS:
430         return strstriW( a, b ) ? 1 : 0;
431     case COND_LHS:
432     case COND_RHS:
433     case COND_ILHS:
434     case COND_IRHS:
435         ERR("unimplemented string comparison\n");
436         break;
437     default:
438         ERR("invalid integer operator\n");
439         return 0;
440     }
441     return 0;
442 }
443
444
445 static INT compare_int( INT a, INT operator, INT b )
446 {
447     switch (operator)
448     {
449     case COND_LT:
450     case COND_ILT:
451         return a < b;
452     case COND_GT:
453     case COND_IGT:
454         return a > b;
455     case COND_EQ:
456     case COND_IEQ:
457         return a == b;
458     case COND_NE:
459     case COND_INE:
460         return a != b;
461     case COND_GE:
462     case COND_IGE:
463         return a >= b;
464     case COND_LE:
465     case COND_ILE:
466         return a >= b;
467     case COND_SS:
468     case COND_ISS:
469         return ( a & b ) ? 1 : 0;
470     case COND_RHS:
471         return ( ( a & 0xffff ) == b ) ? 1 : 0;
472     case COND_LHS:
473         return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0;
474     default:
475         ERR("invalid integer operator\n");
476         return 0;
477     }
478     return 0;
479 }
480
481
482 static int COND_IsIdent( WCHAR x )
483 {
484     return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) 
485             || ( x == '#' ) || (x == '.') );
486 }
487
488 static int COND_GetOperator( COND_input *cond )
489 {
490     static const struct {
491         const WCHAR str[4];
492         int id;
493     } table[] = {
494         { {'~','=',0},     COND_IEQ },
495         { {'~','>','=',0}, COND_ILE },
496         { {'~','>','<',0}, COND_ISS },
497         { {'~','>','>',0}, COND_IRHS },
498         { {'~','>',0},     COND_ILT },
499         { {'~','<','>',0}, COND_INE },
500         { {'~','<','=',0}, COND_IGE },
501         { {'~','<','<',0}, COND_ILHS },
502         { {'~','<',0},     COND_IGT },
503         { {'>','=',0},     COND_GE  },
504         { {'>','<',0},     COND_SS  },
505         { {'>','>',0},     COND_LHS },
506         { {'>',0},         COND_GT  },
507         { {'<','>',0},     COND_NE  },
508         { {'<','=',0},     COND_LE  },
509         { {'<','<',0},     COND_RHS },
510         { {'<',0},         COND_LT  },
511         { {0},             0        }
512     };
513     LPCWSTR p = &cond->str[cond->n];
514     int i = 0, len;
515
516     while ( 1 )
517     {
518         len = lstrlenW( table[i].str );
519         if ( !len || 0 == strncmpW( table[i].str, p, len ) )
520             break;
521         i++;
522     }
523     cond->n += len;
524     return table[i].id;
525 }
526
527 static int COND_GetOne( struct cond_str *str, COND_input *cond )
528 {
529     int rc, len = 1;
530     WCHAR ch;
531
532     str->data = &cond->str[cond->n];
533
534     ch = str->data[0];
535
536     switch( ch )
537     {
538     case 0: return 0;
539     case '(': rc = COND_LPAR; break;
540     case ')': rc = COND_RPAR; break;
541     case '&': rc = COND_AMPER; break;
542     case '!': rc = COND_EXCLAM; break;
543     case '$': rc = COND_DOLLARS; break;
544     case '?': rc = COND_QUESTION; break;
545     case '%': rc = COND_PERCENT; break;
546     case ' ': rc = COND_SPACE; break;
547     case '=': rc = COND_EQ; break;
548         break;
549
550     case '~':
551     case '<':
552     case '>':
553         rc = COND_GetOperator( cond );
554         if (!rc)
555             rc = COND_ERROR;
556         return rc;
557     default:
558         rc = 0;
559     }
560
561     if ( rc )
562     {
563         cond->n += len;
564         return rc;
565     }
566
567     if (ch == '"' )
568     {
569         LPCWSTR p = strchrW( str->data + 1, '"' );
570         if (!p)
571             return COND_ERROR;
572         len = p - str->data + 1;
573         rc = COND_LITER;
574     }
575     else if( COND_IsAlpha( ch ) )
576     {
577         static const WCHAR szNot[] = {'N','O','T',0};
578         static const WCHAR szAnd[] = {'A','N','D',0};
579         static const WCHAR szXor[] = {'X','O','R',0};
580         static const WCHAR szEqv[] = {'E','Q','V',0};
581         static const WCHAR szImp[] = {'I','M','P',0};
582         static const WCHAR szOr[] = {'O','R',0};
583
584         while( COND_IsIdent( str->data[len] ) )
585             len++;
586         rc = COND_IDENT;
587
588         if ( len == 3 )
589         {
590             if ( !strncmpiW( str->data, szNot, len ) )
591                 rc = COND_NOT;
592             else if( !strncmpiW( str->data, szAnd, len ) )
593                 rc = COND_AND;
594             else if( !strncmpiW( str->data, szXor, len ) )
595                 rc = COND_XOR;
596             else if( !strncmpiW( str->data, szEqv, len ) )
597                 rc = COND_EQV;
598             else if( !strncmpiW( str->data, szImp, len ) )
599                 rc = COND_IMP;
600         }
601         else if( (len == 2) && !strncmpiW( str->data, szOr, len ) )
602             rc = COND_OR;
603     }
604     else if( COND_IsNumber( ch ) )
605     {
606         while( COND_IsNumber( str->data[len] ) )
607             len++;
608         rc = COND_NUMBER;
609     }
610     else
611     {
612         ERR("Got unknown character %c(%x)\n",ch,ch);
613         return COND_ERROR;
614     }
615
616     cond->n += len;
617     str->len = len;
618
619     return rc;
620 }
621
622 static int COND_lex( void *COND_lval, COND_input *cond )
623 {
624     int rc;
625     struct cond_str *str = COND_lval;
626
627     do {
628         rc = COND_GetOne( str, cond );
629     } while (rc == COND_SPACE);
630     
631     return rc;
632 }
633
634 static LPWSTR COND_GetString( struct cond_str *str )
635 {
636     LPWSTR ret;
637
638     ret = msi_alloc( (str->len+1) * sizeof (WCHAR) );
639     if( ret )
640     {
641         memcpy( ret, str->data, str->len * sizeof(WCHAR));
642         ret[str->len]=0;
643     }
644     TRACE("Got identifier %s\n",debugstr_w(ret));
645     return ret;
646 }
647
648 static LPWSTR COND_GetLiteral( struct cond_str *str )
649 {
650     LPWSTR ret;
651
652     ret = msi_alloc( (str->len-1) * sizeof (WCHAR) );
653     if( ret )
654     {
655         memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) );
656         ret[str->len - 2]=0;
657     }
658     TRACE("Got literal %s\n",debugstr_w(ret));
659     return ret;
660 }
661
662 static int COND_error(const char *str)
663 {
664     TRACE("%s\n", str );
665     return 0;
666 }
667
668 MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
669 {
670     COND_input cond;
671     MSICONDITION r;
672
673     TRACE("%s\n", debugstr_w( szCondition ) );
674
675     if ( szCondition == NULL )
676         return MSICONDITION_NONE;
677
678     cond.package = package;
679     cond.str   = szCondition;
680     cond.n     = 0;
681     cond.result = MSICONDITION_ERROR;
682     
683     if ( !COND_parse( &cond ) )
684         r = cond.result;
685     else
686         r = MSICONDITION_ERROR;
687
688     TRACE("%i <- %s\n", r, debugstr_w(szCondition));
689     return r;
690 }
691
692 MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition )
693 {
694     MSIPACKAGE *package;
695     UINT ret;
696
697     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
698     if( !package)
699         return MSICONDITION_ERROR;
700     ret = MSI_EvaluateConditionW( package, szCondition );
701     msiobj_release( &package->hdr );
702     return ret;
703 }
704
705 MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition )
706 {
707     LPWSTR szwCond = NULL;
708     MSICONDITION r;
709
710     szwCond = strdupAtoW( szCondition );
711     if( szCondition && !szwCond )
712         return MSICONDITION_ERROR;
713
714     r = MsiEvaluateConditionW( hInstall, szwCond );
715     msi_free( szwCond );
716     return r;
717 }