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