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