Release 980601
[wine] / tools / wrc / parser.y
1 %{
2 /*
3  * Copyright  Martin von Loewis, 1994
4  * Copyright 1998 Bertho A. Stultiens (BS)
5  *
6  * 25-May-1998 BS       - Found out that I need to support language, version
7  *                        and characteristics in inline resources (bitmap,
8  *                        cursor, etc) but they can also be specified with
9  *                        a filename. This renders my filename-scanning scheme
10  *                        worthless. Need to build newline parsing to solve
11  *                        this one.
12  *                        It will come with version 1.1.0 (sigh).
13  *
14  * 19-May-1998 BS       - Started to build a builtin preprocessor
15  *
16  * 30-Apr-1998 BS       - Redid the stringtable parsing/handling. My previous
17  *                        ideas had some serious flaws.
18  *
19  * 27-Apr-1998 BS       - Removed a lot of dead comments and put it in a doc
20  *                        file.
21  *
22  * 21-Apr-1998 BS       - Added correct behavior for cursors and icons.
23  *                      - This file is growing too big. It is time to strip
24  *                        things and put it in a support file.
25  *
26  * 19-Apr-1998 BS       - Tagged the stringtable resource so that only one
27  *                        resource will be created. This because the table
28  *                        has a different layout than other resources. The
29  *                        table has to be sorted, and divided into smaller
30  *                        resource entries (see comment in source).
31  *
32  * 17-Apr-1998 BS       - Almost all strings, including identifiers, are parsed
33  *                        as string_t which include unicode strings upon
34  *                        input.
35  *                      - Parser now emits a warning when compiling win32
36  *                        extensions in win16 mode.
37  *
38  * 16-Apr-1998 BS       - Raw data elements are now *optionally* seperated
39  *                        by commas. Read the comments in file sq2dq.l.
40  *                      - FIXME: there are instances in the source that rely
41  *                        on the fact that int==32bit and pointers are int size.
42  *                      - Fixed the conflict in menuex by changing a rule
43  *                        back into right recursion. See note in source.
44  *                      - UserType resources cannot have an expression as its
45  *                        typeclass. See note in source.
46  *
47  * 15-Apr-1998 BS       - Changed all right recursion into left recursion to
48  *                        get reduction of the parsestack.
49  *                        This also helps communication between bison and flex.
50  *                        Main advantage is that the Empty rule gets reduced
51  *                        first, which is used to allocate/link things.
52  *                        It also added a shift/reduce conflict in the menuex
53  *                        handling, due to expression/option possibility,
54  *                        although not serious.
55  *
56  * 14-Apr-1998 BS       - Redone almost the entire parser. We're not talking
57  *                        about making it more efficient, but readable (for me)
58  *                        and slightly easier to expand/change.
59  *                        This is done primarily by using more reduce states
60  *                        with many (intuitive) types for the various resource
61  *                        statements.
62  *                      - Added expression handling for all resources where a
63  *                        number is accepted (not only for win32). Also added
64  *                        multiply and division (not MS compatible, but handy).
65  *                        Unary minus introduced a shift/reduce conflict, but
66  *                        it is not serious.
67  *
68  * 13-Apr-1998 BS       - Reordered a lot of things
69  *                      - Made the source more readable
70  *                      - Added Win32 resource definitions
71  *                      - Corrected syntax problems with an old yacc (;)
72  *                      - Added extra comment about grammar
73  */
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <stdarg.h>
77 #include <assert.h>
78 #include <ctype.h>
79
80 #include <config.h>
81 #include "wrc.h"
82 #include "utils.h"
83 #include "newstruc.h"
84 #include "dumpres.h"
85 #include "preproc.h"
86 #include "parser.h"
87
88 #ifdef __BORLANDC__
89 #pragma warn -sig
90 #endif
91
92 DWORD andmask;          /* Used to parse 'NOT NUMBER' expressions */
93 int indialog = 0;       /* Signal flex that we're parsing a dialog */
94 int want_rscname = 0;   /* Set when a resource's name is required */
95 stringtable_t *tagstt;  /* Stringtable tag.
96                          * It is set while parsing a stringtable to one of
97                          * the stringtables in the sttres list or a new one
98                          * if the language was not parsed before.
99                          */
100 stringtable_t *sttres;  /* Stringtable resources. This holds the list of
101                          * stringtables with different lanuages
102                          */
103 /* Set to the current options of the currently scanning stringtable */
104 static int *tagstt_memopt;
105 static characts_t *tagstt_characts;
106 static version_t *tagstt_version;
107
108 /* Prototypes of here defined functions */
109 void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur);
110 void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico);
111 int alloc_cursor_id(void);
112 int alloc_icon_id(void);
113 void ins_stt_entry(stt_entry_t *ste);
114 int check_stt_entry(stringtable_t *tabs, stt_entry_t *ste);
115 event_t *get_event_head(event_t *p);
116 control_t *get_control_head(control_t *p);
117 ver_value_t *get_ver_value_head(ver_value_t *p);
118 ver_block_t *get_ver_block_head(ver_block_t *p);
119 resource_t *get_resource_head(resource_t *p);
120 menuex_item_t *get_itemex_head(menuex_item_t *p);
121 menu_item_t *get_item_head(menu_item_t *p);
122 raw_data_t *merge_raw_data_str(raw_data_t *r1, string_t *str);
123 raw_data_t *merge_raw_data_int(raw_data_t *r1, int i);
124 raw_data_t *merge_raw_data(raw_data_t *r1, raw_data_t *r2);
125 raw_data_t *str2raw_data(string_t *str);
126 raw_data_t *int2raw_data(int i);
127 raw_data_t *load_file(string_t *name);
128 itemex_opt_t *new_itemex_opt(int id, int type, int state, int helpid);
129 event_t *add_string_event(string_t *key, int id, int flags, event_t *prev);
130 event_t *add_event(int key, int id, int flags, event_t *prev);
131 dialogex_t *dialogex_version(version_t *v, dialogex_t *dlg);
132 dialogex_t *dialogex_characteristics(characts_t *c, dialogex_t *dlg);
133 dialogex_t *dialogex_language(language_t *l, dialogex_t *dlg);
134 dialogex_t *dialogex_menu(name_id_t *m, dialogex_t *dlg);
135 dialogex_t *dialogex_class(name_id_t *n, dialogex_t *dlg);
136 dialogex_t *dialogex_font(font_id_t *f, dialogex_t *dlg);
137 dialogex_t *dialogex_caption(string_t *s, dialogex_t *dlg);
138 dialogex_t *dialogex_exstyle(int st, dialogex_t *dlg);
139 dialogex_t *dialogex_style(int st, dialogex_t *dlg);
140 name_id_t *convert_ctlclass(name_id_t *cls);
141 control_t *ins_ctrl(int type, int style, control_t *ctrl, control_t *prev);
142 dialog_t *dialog_version(version_t *v, dialog_t *dlg);
143 dialog_t *dialog_characteristics(characts_t *c, dialog_t *dlg);
144 dialog_t *dialog_language(language_t *l, dialog_t *dlg);
145 dialog_t *dialog_menu(name_id_t *m, dialog_t *dlg);
146 dialog_t *dialog_class(name_id_t *n, dialog_t *dlg);
147 dialog_t *dialog_font(font_id_t *f, dialog_t *dlg);
148 dialog_t *dialog_caption(string_t *s, dialog_t *dlg);
149 dialog_t *dialog_exstyle(int st, dialog_t *dlg);
150 dialog_t *dialog_style(int st, dialog_t *dlg);
151 resource_t *build_stt_resources(stringtable_t *stthead);
152 stringtable_t *find_stringtable(lvc_t *lvc);
153
154 %}
155 %union{
156         string_t        *str;
157         int             num;
158         int             *iptr;
159         resource_t      *res;
160         accelerator_t   *acc;
161         bitmap_t        *bmp;
162         cursor_t        *cur;
163         cursor_group_t  *curg;
164         dialog_t        *dlg;
165         dialogex_t      *dlgex;
166         font_t          *fnt;
167         icon_t          *ico;
168         icon_group_t    *icog;
169         menu_t          *men;
170         menuex_t        *menex;
171         rcdata_t        *rdt;
172         stringtable_t   *stt;
173         stt_entry_t     *stte;
174         user_t          *usr;
175         messagetable_t  *msg;
176         versioninfo_t   *veri;
177         control_t       *ctl;
178         name_id_t       *nid;
179         font_id_t       *fntid;
180         language_t      *lan;
181         version_t       *ver;
182         characts_t      *chars;
183         event_t         *event;
184         menu_item_t     *menitm;
185         menuex_item_t   *menexitm;
186         itemex_opt_t    *exopt;
187         raw_data_t      *raw;
188         lvc_t           *lvc;
189         ver_value_t     *val;
190         ver_block_t     *blk;
191         ver_words_t     *verw;
192 }
193
194 %token tIF tIFDEF tIFNDEF tELSE tELIF tENDIF tDEFINED tNL
195 %token tTYPEDEF tEXTERN
196 %token <num> NUMBER
197 %token <str> tSTRING IDENT FILENAME
198 %token <raw> RAWDATA
199 %token ACCELERATORS tBITMAP CURSOR DIALOG DIALOGEX MENU MENUEX MESSAGETABLE
200 %token RCDATA VERSIONINFO STRINGTABLE FONT ICON
201 %token AUTO3STATE AUTOCHECKBOX AUTORADIOBUTTON CHECKBOX DEFPUSHBUTTON
202 %token PUSHBUTTON RADIOBUTTON STATE3 /* PUSHBOX */
203 %token GROUPBOX COMBOBOX LISTBOX SCROLLBAR
204 %token CONTROL EDITTEXT
205 %token RTEXT CTEXT LTEXT
206 %token BLOCK VALUE
207 %token SHIFT ALT ASCII VIRTKEY GRAYED CHECKED INACTIVE NOINVERT
208 %token tPURE IMPURE DISCARDABLE LOADONCALL PRELOAD tFIXED MOVEABLE
209 %token CLASS CAPTION CHARACTERISTICS EXSTYLE STYLE VERSION LANGUAGE
210 %token FILEVERSION PRODUCTVERSION FILEFLAGSMASK FILEOS FILETYPE FILEFLAGS FILESUBTYPE
211 %token MENUBARBREAK MENUBREAK MENUITEM POPUP SEPARATOR
212 %token HELP
213 %token tSTRING IDENT RAWDATA
214 %token tBEGIN tEND
215 %left LOGOR
216 %left LOGAND
217 %left '|'
218 %left '^'
219 %left '&'
220 %left EQ NE
221 %left '<' LTE '>' GTE
222 %left '+' '-'
223 %left '*' '/'
224 %right '~' '!' NOT
225
226 %type <res>     resource_file resource resources resource_definition
227 %type <stt>     stringtable strings
228 %type <fnt>     font
229 %type <icog>    icon
230 %type <acc>     accelerators
231 %type <event>   events
232 %type <bmp>     bitmap
233 %type <curg>    cursor
234 %type <dlg>     dialog dlg_attributes
235 %type <ctl>     ctrls gen_ctrl lab_ctrl ctrl_desc iconinfo
236 %type <iptr>    optional_style helpid
237 %type <dlgex>   dialogex dlgex_attribs
238 %type <ctl>     exctrls gen_exctrl lab_exctrl exctrl_desc
239 %type <rdt>     rcdata
240 %type <raw>     raw_data raw_elements opt_data
241 %type <veri>    versioninfo fix_version
242 %type <verw>    ver_words
243 %type <blk>     ver_blocks ver_block
244 %type <val>     ver_values ver_value
245 %type <men>     menu
246 %type <menitm>  item_definitions menu_body
247 %type <menex>   menuex
248 %type <menexitm> itemex_definitions menuex_body
249 %type <exopt>   itemex_p_options itemex_options
250 %type <msg>     messagetable
251 %type <usr>     userres
252 %type <num>     item_options
253 %type <nid>     nameid ctlclass usertype
254 %type <num>     acc_opt
255 %type <iptr>    loadmemopts lamo lama
256 %type <fntid>   opt_font opt_exfont
257 %type <lvc>     opt_lvc
258 %type <lan>     opt_language
259 %type <chars>   opt_characts
260 %type <ver>     opt_version
261 %type <num>     expr xpr dummy
262 %type <iptr>    e_expr
263 %type <iptr>    pp_expr pp_constant
264
265 %%
266
267 resource_file
268         : resources {
269                 resource_t *rsc;
270                 /* First add stringtables to the resource-list */
271                 rsc = build_stt_resources(sttres);
272                 /* 'build_stt_resources' returns a head and $1 is a tail */
273                 if($1)
274                 {
275                         $1->next = rsc;
276                         if(rsc)
277                                 rsc->prev = $1;
278                 }
279                 else
280                         $1 = rsc;
281                 /* Final statement before were done */
282                 resource_top = get_resource_head($1);
283                 }
284         ;
285
286 /* Resources are put into a linked list */
287 resources
288         : /* Empty */           { $$ = NULL; want_rscname = 1; }
289         | resources resource    {
290                 if($2)
291                 {
292                         resource_t *tail = $2;
293                         resource_t *head = $2;
294                         while(tail->next)
295                                 tail = tail->next;
296                         while(head->prev)
297                                 head = head->prev;
298                         head->prev = $1;
299                         if($1)
300                                 $1->next = head;
301                         $$ = tail;
302                 }
303                 else if($1)
304                 {
305                         resource_t *tail = $1;
306                         while(tail->next)
307                                 tail = tail->next;
308                         $$ = tail;
309                 }
310                 else
311                         $$ = NULL;
312                 want_rscname = 1;
313                 }
314         | resources preprocessor                { $$ = $1; want_rscname = 1; }
315         | resources cjunk                       { $$ = $1; want_rscname = 1; }
316         ;
317
318 /* The buildin preprocessor */
319 preprocessor
320         : tIF pp_expr tNL       { pop_start(); push_if($2 ? *($2) : 0, 0, 0); if($2) free($2);}
321         | tIFDEF IDENT tNL      { pop_start(); push_if(pp_lookup($2->str.cstr) != NULL, 0, 0); }
322         | tIFNDEF IDENT tNL     { pop_start(); push_if(pp_lookup($2->str.cstr) == NULL, 0, 0); }
323         | tELIF pp_expr tNL     { pop_start(); push_if($2 ? *($2) : 0, pop_if(), 0); if($2) free($2); }
324         | tELSE tNL             { pop_start(); push_if(1, pop_if(), 0); }
325         | tENDIF tNL            { pop_if(); }
326         ;
327
328 pp_expr : pp_constant                   { $$ = $1; }
329         | pp_expr LOGOR pp_expr         { $$ = new_int($1 && $3 ? (*$1 || *$3) : 0); if($1) free($1); if($3) free($3); }
330         | pp_expr LOGAND pp_expr        { $$ = new_int($1 && $3 ? (*$1 && *$3) : 0); if($1) free($1); if($3) free($3); }
331         | pp_expr '+' pp_expr           { $$ = new_int($1 && $3 ? (*$1  + *$3) : 0); if($1) free($1); if($3) free($3); }
332         | pp_expr '-' pp_expr           { $$ = new_int($1 && $3 ? (*$1  - *$3) : 0); if($1) free($1); if($3) free($3); }
333         | pp_expr '^' pp_expr           { $$ = new_int($1 && $3 ? (*$1  ^ *$3) : 0); if($1) free($1); if($3) free($3); }
334         | pp_expr EQ pp_expr            { $$ = new_int($1 && $3 ? (*$1 == *$3) : 0); if($1) free($1); if($3) free($3); }
335         | pp_expr NE pp_expr            { $$ = new_int($1 && $3 ? (*$1 != *$3) : 0); if($1) free($1); if($3) free($3); }
336         | pp_expr '<' pp_expr           { $$ = new_int($1 && $3 ? (*$1  < *$3) : 0); if($1) free($1); if($3) free($3); }
337         | pp_expr '>' pp_expr           { $$ = new_int($1 && $3 ? (*$1  > *$3) : 0); if($1) free($1); if($3) free($3); }
338         | pp_expr LTE pp_expr           { $$ = new_int($1 && $3 ? (*$1 <= *$3) : 0); if($1) free($1); if($3) free($3); }
339         | pp_expr GTE pp_expr           { $$ = new_int($1 && $3 ? (*$1 >= *$3) : 0); if($1) free($1); if($3) free($3); }
340         | '~' pp_expr                   { $$ = $2; if($2) *$2 = ~(*$2); }
341         | '+' pp_expr                   { $$ = $2; }
342         | '-' pp_expr                   { $$ = $2; if($2) *$2 = -(*$2); }
343         | '!' pp_expr                   { $$ = $2; if($2) *$2 = !(*$2); }
344         | '(' pp_expr ')'               { $$ = $2; }
345         ;
346
347 pp_constant
348         : NUMBER                        { $$ = new_int($1); }
349         | IDENT                         { $$ = NULL; }
350         | tDEFINED IDENT                { $$ = new_int(pp_lookup($2->str.cstr) != NULL); }
351         | tDEFINED '(' IDENT ')'        { $$ = new_int(pp_lookup($3->str.cstr) != NULL); }
352         ;
353
354 /* C ignore stuff */
355 cjunk   : tTYPEDEF                      { strip_til_semicolon(); }
356         | tEXTERN                       { strip_til_semicolon(); }
357         | IDENT IDENT                   { strip_til_semicolon(); }
358         | IDENT '('                     { strip_til_parenthesis(); }
359         | IDENT '*'                     { strip_til_semicolon(); }
360         ;
361
362 /* Parse top level resource definitions etc. */
363 resource
364         : nameid resource_definition {
365                 $$ = $2;
366                 if($$)
367                 {
368                         $$->name = $1;
369                         if($1->type == name_ord)
370                         {
371                                 chat("Got %s (%d)",get_typename($2),$1->name.i_name);
372                         }
373                         else if($1->type == name_str)
374                         {
375                                 chat("Got %s (%s)",get_typename($2),$1->name.s_name->str.cstr);
376                         }
377                 }
378                 }
379         | stringtable {
380                 /* Don't do anything, stringtables are converted to
381                  * resource_t structures when we are finished parsing and
382                  * the final rule of the parser is reduced (see above)
383                  */
384                 $$ = NULL;
385                 chat("Got STRINGTABLE");
386                 }
387         | opt_language {
388                 if(!win32)
389                         yywarning("LANGUAGE not supported in 16-bit mode");
390                 if(currentlanguage)
391                         free(currentlanguage);
392                 currentlanguage = $1;
393                 $$ = NULL;
394                 }
395         ;
396
397 /* FIXME:
398  * The problem here is that MENU MENU {...} is a valid (!) resource.
399  * The name-identifier is "MENU". We cannot parse this without generating
400  * an error. It would mean that a list of keywords must be added here
401  * and converted into a valid name_id_t structure.
402  */
403 nameid  : expr  {
404                 $$ = new_name_id();
405                 $$->type = name_ord;
406                 $$->name.i_name = $1;
407                 want_rscname = 0;
408                 }
409         | IDENT {
410                 $$ = new_name_id();
411                 $$->type = name_str;
412                 $$->name.s_name = $1;
413                 want_rscname = 0;
414                 }
415         ;
416
417 /* get the value for a single resource*/
418 resource_definition
419         : accelerators  { $$ = new_resource(res_acc, $1, $1->memopt, $1->lvc.language); }
420         | bitmap        { $$ = new_resource(res_bmp, $1, $1->memopt, currentlanguage); }
421         | cursor {
422                 resource_t *rsc;
423                 cursor_t *cur;
424                 $$ = rsc = new_resource(res_curg, $1, $1->memopt, currentlanguage);
425                 for(cur = $1->cursorlist; cur; cur = cur->next)
426                 {
427                         rsc->prev = new_resource(res_cur, cur, $1->memopt, currentlanguage);
428                         rsc->prev->next = rsc;
429                         rsc = rsc->prev;
430                         rsc->name = new_name_id();
431                         rsc->name->type = name_ord;
432                         rsc->name->name.i_name = cur->id;
433                 }
434                 }
435         | dialog        { $$ = new_resource(res_dlg, $1, $1->memopt, $1->lvc.language); }
436         | dialogex {
437                 if(win32)
438                         $$ = new_resource(res_dlgex, $1, $1->memopt, $1->lvc.language);
439                 else
440                         $$ = NULL;
441                 }
442         | font          { $$=new_resource(res_fnt, $1, $1->memopt, currentlanguage); }
443         | icon {
444                 resource_t *rsc;
445                 icon_t *ico;
446                 $$ = rsc = new_resource(res_icog, $1, $1->memopt, currentlanguage);
447                 for(ico = $1->iconlist; ico; ico = ico->next)
448                 {
449                         rsc->prev = new_resource(res_ico, ico, $1->memopt, currentlanguage);
450                         rsc->prev->next = rsc;
451                         rsc = rsc->prev;
452                         rsc->name = new_name_id();
453                         rsc->name->type = name_ord;
454                         rsc->name->name.i_name = ico->id;
455                 }
456                 }
457         | menu          { $$ = new_resource(res_men, $1, $1->memopt, $1->lvc.language); }
458         | menuex {
459                 if(win32)
460                         $$ = new_resource(res_menex, $1, $1->memopt, $1->lvc.language);
461                 else
462                         $$ = NULL;
463                 }
464         | messagetable  { $$ = new_resource(res_msg, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, currentlanguage); }
465         | rcdata        { $$ = new_resource(res_rdt, $1, $1->memopt, $1->lvc.language); }
466         | userres       { $$ = new_resource(res_usr, $1, $1->memopt, currentlanguage); }
467         | versioninfo   { $$ = new_resource(res_ver, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, currentlanguage); }
468         ;
469
470 /* ------------------------------ Bitmap ------------------------------ */
471 bitmap  : tBITMAP loadmemopts FILENAME  { $$ = new_bitmap(load_file($3), $2); }
472         | tBITMAP loadmemopts raw_data  { $$ = new_bitmap($3, $2); }
473         ;
474
475 /* ------------------------------ Cursor ------------------------------ */
476 cursor  : CURSOR loadmemopts FILENAME   { $$ = new_cursor_group(load_file($3), $2); }
477         | CURSOR loadmemopts raw_data   { $$ = new_cursor_group($3, $2); }
478         ;
479
480 /* ------------------------------ Font ------------------------------ */
481 /* FIXME: Should we allow raw_data here? */
482 font    : FONT loadmemopts FILENAME     { $$ = new_font(load_file($3), $2); }
483         ;
484
485 /* ------------------------------ Icon ------------------------------ */
486 icon    : ICON loadmemopts FILENAME     { $$ = new_icon_group(load_file($3), $2); }
487         | ICON loadmemopts raw_data     { $$ = new_icon_group($3, $2); }
488         ;
489
490 /* ------------------------------ MessageTable ------------------------------ */
491 /* It might be interesting to implement the MS Message compiler here as well
492  * to get everything in one source. Might be a future project.
493  */
494 messagetable
495         : MESSAGETABLE FILENAME {
496                 if(!win32)
497                         yywarning("MESSAGETABLE not supported in 16-bit mode");
498                 $$ = new_messagetable(load_file($2));
499                 }
500         ;
501
502 /* ------------------------------ RCData ------------------------------ */
503 rcdata  : RCDATA loadmemopts opt_lvc raw_data {
504                 $$ = new_rcdata($4, $2);
505                 if($3)
506                 {
507                         $$->lvc = *($3);
508                         free($3);
509                 }
510                 if(!$$->lvc.language)
511                         $$->lvc.language = dup_language(currentlanguage);
512                 }
513         ;
514
515 /* ------------------------------ UserType ------------------------------ */
516 userres : usertype loadmemopts FILENAME { $$ = new_user($1, load_file($3), $2); }
517         | usertype loadmemopts raw_data { $$ = new_user($1, $3, $2); }
518         ;
519
520 /* NOTE: This here is an exception where I do not allow an expression.
521  * Reason for this is that it is not possible to set the 'yywf' condition
522  * for flex if loadmemopts is empty. Reading an expression requires a
523  * lookahead to determine its end. In this case here, that would mean that
524  * the filename has been read as IDENT or tSTRING, which is incorrect.
525  * Note also that IDENT cannot be used as a file-name because it is lacking
526  * the '.'.
527  */
528
529 /* I also allow string identifiers as classtypes. Not MS implemented, but
530  * seems to be reasonable to implement.
531  */
532 /* Allowing anything else than NUMBER makes it very hard to get rid of
533  * prototypes. So, I remove IDENT to be able to get prototypes out of the
534  * world.
535  */
536 usertype: NUMBER {
537                 $$ = new_name_id();
538                 $$->type = name_ord;
539                 $$->name.i_name = $1;
540                 set_yywf();
541                 }
542 /*      | IDENT {
543                 $$ = new_name_id();
544                 $$->type = name_str;
545                 $$->name.s_name = $1;
546                 set_yywf();
547                 }
548 */      | tSTRING {
549                 $$ = new_name_id();
550                 $$->type = name_str;
551                 $$->name.s_name = $1;
552                 set_yywf();
553                 }
554         ;
555
556 /* ------------------------------ Accelerator ------------------------------ */
557 accelerators
558         : ACCELERATORS loadmemopts opt_lvc tBEGIN events tEND {
559                 $$ = new_accelerator();
560                 if($2)
561                 {
562                         $$->memopt = *($2);
563                         free($2);
564                 }
565                 else
566                 {
567                         $$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
568                 }
569                 if(!$5)
570                         yyerror("Accelerator table must have at least one entry");
571                 $$->events = get_event_head($5);
572                 if($3)
573                 {
574                         $$->lvc = *($3);
575                         free($3);
576                 }
577                 if(!$$->lvc.language)
578                         $$->lvc.language = dup_language(currentlanguage);
579                 }
580         ;
581
582 events  : /* Empty */                           { $$=NULL; }
583         | events tSTRING ',' expr acc_opt       { $$=add_string_event($2, $4, $5, $1); }
584         | events expr ',' expr acc_opt          { $$=add_event($2, $4, $5, $1); }
585         ;
586
587 acc_opt : /* Empty */           { $$=0; }
588         | acc_opt ',' NOINVERT  { $$=$1 | WRC_AF_NOINVERT; }
589         | acc_opt ',' SHIFT     { $$=$1 | WRC_AF_SHIFT; }
590         | acc_opt ',' CONTROL   { $$=$1 | WRC_AF_CONTROL; }
591         | acc_opt ',' ALT       { $$=$1 | WRC_AF_ALT; }
592         | acc_opt ',' ASCII     { $$=$1 | WRC_AF_ASCII; }
593         | acc_opt ',' VIRTKEY   { $$=$1 | WRC_AF_VIRTKEY; }
594         ;
595
596 /* ------------------------------ Dialog ------------------------------ */
597 /* FIXME: Support EXSTYLE in the dialog line itself */
598 dialog  : DIALOG loadmemopts expr ',' expr ',' expr ',' expr dlg_attributes
599           tBEGIN  ctrls tEND {
600                 if($2)
601                 {
602                         $10->memopt = *($2);
603                         free($2);
604                 }
605                 else
606                         $10->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
607                 $10->x = $3;
608                 $10->y = $5;
609                 $10->width = $7;
610                 $10->height = $9;
611                 $10->controls = get_control_head($12);
612                 $$ = $10;
613                 if(!$$->gotstyle)
614                 {
615                         $$->style = WS_POPUP;
616                         $$->gotstyle = TRUE;
617                 }
618                 if($$->title)
619                         $$->style |= WS_CAPTION;
620                 if($$->font)
621                         $$->style |= DS_SETFONT;
622                 indialog = FALSE;
623                 if(!$$->lvc.language)
624                         $$->lvc.language = dup_language(currentlanguage);
625                 }
626         ;
627
628 dlg_attributes
629         : /* Empty */                   { $$=new_dialog(); }
630         | dlg_attributes STYLE expr     { $$=dialog_style($3,$1); }
631         | dlg_attributes EXSTYLE expr   { $$=dialog_exstyle($3,$1); }
632         | dlg_attributes CAPTION tSTRING { $$=dialog_caption($3,$1); }
633         | dlg_attributes opt_font       { $$=dialog_font($2,$1); }
634         | dlg_attributes CLASS nameid   { $$=dialog_class($3,$1); }
635         | dlg_attributes MENU nameid    { $$=dialog_menu($3,$1); }
636         | dlg_attributes opt_language   { $$=dialog_language($2,$1); }
637         | dlg_attributes opt_characts   { $$=dialog_characteristics($2,$1); }
638         | dlg_attributes opt_version    { $$=dialog_version($2,$1); }
639         ;
640
641 ctrls   : /* Empty */                           { $$ = NULL; }
642         | ctrls CONTROL         gen_ctrl        { $$=ins_ctrl(-1, 0, $3, $1); }
643         | ctrls EDITTEXT        ctrl_desc       { $$=ins_ctrl(CT_EDIT, 0, $3, $1); }
644         | ctrls LISTBOX         ctrl_desc       { $$=ins_ctrl(CT_LISTBOX, 0, $3, $1); }
645         | ctrls COMBOBOX        ctrl_desc       { $$=ins_ctrl(CT_COMBOBOX, 0, $3, $1); }
646         | ctrls SCROLLBAR       ctrl_desc       { $$=ins_ctrl(CT_SCROLLBAR, 0, $3, $1); }
647         | ctrls CHECKBOX        lab_ctrl        { $$=ins_ctrl(CT_BUTTON, BS_CHECKBOX, $3, $1); }
648         | ctrls DEFPUSHBUTTON   lab_ctrl        { $$=ins_ctrl(CT_BUTTON, BS_DEFPUSHBUTTON, $3, $1); }
649         | ctrls GROUPBOX        lab_ctrl        { $$=ins_ctrl(CT_BUTTON, BS_GROUPBOX, $3, $1);}
650         | ctrls PUSHBUTTON      lab_ctrl        { $$=ins_ctrl(CT_BUTTON, BS_PUSHBUTTON, $3, $1); }
651 /*      | ctrls PUSHBOX         lab_ctrl        { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
652         | ctrls RADIOBUTTON     lab_ctrl        { $$=ins_ctrl(CT_BUTTON, BS_RADIOBUTTON, $3, $1); }
653         | ctrls AUTO3STATE      lab_ctrl        { $$=ins_ctrl(CT_BUTTON, BS_AUTO3STATE, $3, $1); }
654         | ctrls STATE3          lab_ctrl        { $$=ins_ctrl(CT_BUTTON, BS_3STATE, $3, $1); }
655         | ctrls AUTOCHECKBOX    lab_ctrl        { $$=ins_ctrl(CT_BUTTON, BS_AUTOCHECKBOX, $3, $1); }
656         | ctrls AUTORADIOBUTTON lab_ctrl        { $$=ins_ctrl(CT_BUTTON, BS_AUTORADIOBUTTON, $3, $1); }
657         | ctrls LTEXT           lab_ctrl        { $$=ins_ctrl(CT_STATIC, SS_LEFT, $3, $1); }
658         | ctrls CTEXT           lab_ctrl        { $$=ins_ctrl(CT_STATIC, SS_CENTER, $3, $1); }
659         | ctrls RTEXT           lab_ctrl        { $$=ins_ctrl(CT_STATIC, SS_RIGHT, $3, $1); }
660         /* special treatment for icons, as the extent is optional */
661         | ctrls ICON tSTRING ',' expr ',' expr ',' expr iconinfo {
662                 $10->title = $3;
663                 $10->id = $5;
664                 $10->x = $7;
665                 $10->y = $9;
666                 $$ = ins_ctrl(CT_STATIC, SS_ICON, $10, $1);
667                 }
668         ;
669
670 lab_ctrl
671         : tSTRING ',' expr ',' expr ',' expr ',' expr ',' expr optional_style {
672                 $$=new_control();
673                 $$->title = $1;
674                 $$->id = $3;
675                 $$->x = $5;
676                 $$->y = $7;
677                 $$->width = $9;
678                 $$->height = $11;
679                 if($12)
680                 {
681                         $$->style = *($12);
682                         $$->gotstyle = TRUE;
683                         free($12);
684                 }
685                 }
686         ;
687
688 ctrl_desc
689         : expr ',' expr ',' expr ',' expr ',' expr optional_style {
690                 $$ = new_control();
691                 $$->id = $1;
692                 $$->x = $3;
693                 $$->y = $5;
694                 $$->width = $7;
695                 $$->height = $9;
696                 if($10)
697                 {
698                         $$->style = *($10);
699                         $$->gotstyle = TRUE;
700                         free($10);
701                 }
702                 }
703         ;
704
705 iconinfo: /* Empty */
706                 { $$ = new_control(); }
707
708         | ',' expr ',' expr {
709                 $$ = new_control();
710                 $$->width = $2;
711                 $$->height = $4;
712                 }
713         | ',' expr ',' expr ',' expr {
714                 $$ = new_control();
715                 $$->width = $2;
716                 $$->height = $4;
717                 $$->style = $6;
718                 $$->gotstyle = TRUE;
719                 }
720         | ',' expr ',' expr ',' expr ',' expr {
721                 $$ = new_control();
722                 $$->width = $2;
723                 $$->height = $4;
724                 $$->style = $6;
725                 $$->gotstyle = TRUE;
726                 $$->exstyle = $8;
727                 $$->gotexstyle = TRUE;
728                 }
729         ;
730
731 gen_ctrl: tSTRING ',' expr ',' ctlclass ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr {
732                 $$=new_control();
733                 $$->title = $1;
734                 $$->id = $3;
735                 $$->ctlclass = convert_ctlclass($5);
736                 $$->style = $7;
737                 $$->gotstyle = TRUE;
738                 $$->x = $9;
739                 $$->y = $11;
740                 $$->width = $13;
741                 $$->height = $15;
742                 $$->exstyle = $17;
743                 $$->gotexstyle = TRUE;
744                 }
745         | tSTRING ',' expr ',' ctlclass ',' expr ',' expr ',' expr ',' expr ',' expr {
746                 $$=new_control();
747                 $$->title = $1;
748                 $$->id = $3;
749                 $$->ctlclass = convert_ctlclass($5);
750                 $$->style = $7;
751                 $$->gotstyle = TRUE;
752                 $$->x = $9;
753                 $$->y = $11;
754                 $$->width = $13;
755                 $$->height = $15;
756                 }
757         ;
758
759 opt_font
760         : FONT expr ',' tSTRING { $$ = new_font_id($2, $4, 0, 0); }
761         ;
762
763 optional_style          /* Abbused once to get optional ExStyle */
764         : /* Empty */   { $$ = NULL; }
765         | ',' expr      { $$ = new_int($2); }
766         ;
767
768 ctlclass
769         : expr  {
770                 $$ = new_name_id();
771                 $$->type = name_ord;
772                 $$->name.i_name = $1;
773                 }
774         | tSTRING {
775                 $$ = new_name_id();
776                 $$->type = name_str;
777                 $$->name.s_name = $1;
778                 }
779         ;
780
781 /* ------------------------------ DialogEx ------------------------------ */
782 dialogex: DIALOGEX loadmemopts expr ',' expr ',' expr ',' expr helpid dlgex_attribs
783           tBEGIN  exctrls tEND {
784                 if(!win32)
785                         yywarning("DIALOGEX not supported in 16-bit mode");
786                 if($2)
787                 {
788                         $11->memopt = *($2);
789                         free($2);
790                 }
791                 else
792                         $11->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
793                 $11->x = $3;
794                 $11->y = $5;
795                 $11->width = $7;
796                 $11->height = $9;
797                 if($10)
798                 {
799                         $11->helpid = *($10);
800                         $11->gothelpid = TRUE;
801                         free($10);
802                 }
803                 $11->controls = get_control_head($13);
804                 $$ = $11;
805                 if(!$$->gotstyle)
806                 {
807                         $$->style = WS_POPUP;
808                         $$->gotstyle = TRUE;
809                 }
810                 if($$->title)
811                         $$->style |= WS_CAPTION;
812                 if($$->font)
813                         $$->style |= DS_SETFONT;
814                 indialog = FALSE;
815                 if(!$$->lvc.language)
816                         $$->lvc.language = dup_language(currentlanguage);
817                 }
818         ;
819
820 dlgex_attribs
821         : /* Empty */                   { $$=new_dialogex(); }
822         | dlgex_attribs STYLE expr      { $$=dialogex_style($3,$1); }
823         | dlgex_attribs EXSTYLE expr    { $$=dialogex_exstyle($3,$1); }
824         | dlgex_attribs CAPTION tSTRING { $$=dialogex_caption($3,$1); }
825         | dlgex_attribs opt_exfont      { $$=dialogex_font($2,$1); }
826         | dlgex_attribs CLASS nameid    { $$=dialogex_class($3,$1); }
827         | dlgex_attribs MENU nameid     { $$=dialogex_menu($3,$1); }
828         | dlgex_attribs opt_language    { $$=dialogex_language($2,$1); }
829         | dlgex_attribs opt_characts    { $$=dialogex_characteristics($2,$1); }
830         | dlgex_attribs opt_version     { $$=dialogex_version($2,$1); }
831         ;
832
833 exctrls : /* Empty */                           { $$ = NULL; }
834         | exctrls CONTROL       gen_exctrl      { $$=ins_ctrl(-1, 0, $3, $1); }
835         | exctrls EDITTEXT      exctrl_desc     { $$=ins_ctrl(CT_EDIT, 0, $3, $1); }
836         | exctrls LISTBOX       exctrl_desc     { $$=ins_ctrl(CT_LISTBOX, 0, $3, $1); }
837         | exctrls COMBOBOX      exctrl_desc     { $$=ins_ctrl(CT_COMBOBOX, 0, $3, $1); }
838         | exctrls SCROLLBAR     exctrl_desc     { $$=ins_ctrl(CT_SCROLLBAR, 0, $3, $1); }
839         | exctrls CHECKBOX      lab_exctrl      { $$=ins_ctrl(CT_BUTTON, BS_CHECKBOX, $3, $1); }
840         | exctrls DEFPUSHBUTTON lab_exctrl      { $$=ins_ctrl(CT_BUTTON, BS_DEFPUSHBUTTON, $3, $1); }
841         | exctrls GROUPBOX      lab_exctrl      { $$=ins_ctrl(CT_BUTTON, BS_GROUPBOX, $3, $1);}
842         | exctrls PUSHBUTTON    lab_exctrl      { $$=ins_ctrl(CT_BUTTON, BS_PUSHBUTTON, $3, $1); }
843 /*      | exctrls PUSHBOX       lab_exctrl      { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
844         | exctrls RADIOBUTTON   lab_exctrl      { $$=ins_ctrl(CT_BUTTON, BS_RADIOBUTTON, $3, $1); }
845         | exctrls AUTO3STATE    lab_exctrl      { $$=ins_ctrl(CT_BUTTON, BS_AUTO3STATE, $3, $1); }
846         | exctrls STATE3        lab_exctrl      { $$=ins_ctrl(CT_BUTTON, BS_3STATE, $3, $1); }
847         | exctrls AUTOCHECKBOX  lab_exctrl      { $$=ins_ctrl(CT_BUTTON, BS_AUTOCHECKBOX, $3, $1); }
848         | exctrls AUTORADIOBUTTON lab_exctrl    { $$=ins_ctrl(CT_BUTTON, BS_AUTORADIOBUTTON, $3, $1); }
849         | exctrls LTEXT         lab_exctrl      { $$=ins_ctrl(CT_STATIC, SS_LEFT, $3, $1); }
850         | exctrls CTEXT         lab_exctrl      { $$=ins_ctrl(CT_STATIC, SS_CENTER, $3, $1); }
851         | exctrls RTEXT         lab_exctrl      { $$=ins_ctrl(CT_STATIC, SS_RIGHT, $3, $1); }
852         /* special treatment for icons, as the extent is optional */
853         | exctrls ICON tSTRING ',' expr ',' expr ',' expr iconinfo {
854                 $10->title = $3;
855                 $10->id = $5;
856                 $10->x = $7;
857                 $10->y = $9;
858                 $$ = ins_ctrl(CT_STATIC, SS_ICON, $10, $1);
859                 }
860         ;
861
862 gen_exctrl
863         : tSTRING ',' expr ',' ctlclass ',' expr ',' expr ',' expr ',' expr ','
864           expr ',' e_expr helpid opt_data {
865                 $$=new_control();
866                 $$->title = $1;
867                 $$->id = $3;
868                 $$->ctlclass = convert_ctlclass($5);
869                 $$->style = $7;
870                 $$->gotstyle = TRUE;
871                 $$->x = $9;
872                 $$->y = $11;
873                 $$->width = $13;
874                 $$->height = $15;
875                 if($17)
876                 {
877                         $$->exstyle = *($17);
878                         $$->gotexstyle = TRUE;
879                         free($17);
880                 }
881                 if($18)
882                 {
883                         $$->helpid = *($18);
884                         $$->gothelpid = TRUE;
885                         free($18);
886                 }
887                 $$->extra = $19;
888                 }
889         | tSTRING ',' expr ',' ctlclass ',' expr ',' expr ',' expr ',' expr ',' expr opt_data {
890                 $$=new_control();
891                 $$->title = $1;
892                 $$->id = $3;
893                 $$->style = $7;
894                 $$->gotstyle = TRUE;
895                 $$->ctlclass = convert_ctlclass($5);
896                 $$->x = $9;
897                 $$->y = $11;
898                 $$->width = $13;
899                 $$->height = $15;
900                 $$->extra = $16;
901                 }
902         ;
903
904 lab_exctrl
905         : tSTRING ',' expr ',' expr ',' expr ',' expr ',' expr optional_style opt_data {
906                 $$=new_control();
907                 $$->title = $1;
908                 $$->id = $3;
909                 $$->x = $5;
910                 $$->y = $7;
911                 $$->width = $9;
912                 $$->height = $11;
913                 if($12)
914                 {
915                         $$->style = *($12);
916                         $$->gotstyle = TRUE;
917                         free($12);
918                 }
919                 $$->extra = $13;
920                 }
921         ;
922
923 exctrl_desc
924         : expr ',' expr ',' expr ',' expr ',' expr optional_style opt_data {
925                 $$ = new_control();
926                 $$->id = $1;
927                 $$->x = $3;
928                 $$->y = $5;
929                 $$->width = $7;
930                 $$->height = $9;
931                 if($10)
932                 {
933                         $$->style = *($10);
934                         $$->gotstyle = TRUE;
935                         free($10);
936                 }
937                 $$->extra = $11;
938                 }
939         ;
940
941 opt_data: /* Empty */   { $$ = NULL; }
942         | raw_data      { $$ = $1; }
943         ;
944
945 helpid  : /* Empty */   { $$ = NULL; }
946         | ',' expr      { $$ = new_int($2); }
947         ;
948
949 opt_exfont
950         : FONT expr ',' tSTRING ',' expr ',' expr       { $$ = new_font_id($2, $4, $6, $8); }
951         ;
952
953 /* ------------------------------ Menu ------------------------------ */
954 menu    : MENU loadmemopts opt_lvc menu_body {
955                 if(!$4)
956                         yyerror("Menu must contain items");
957                 $$ = new_menu();
958                 if($2)
959                 {
960                         $$->memopt = *($2);
961                         free($2);
962                 }
963                 else
964                         $$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
965                 $$->items = get_item_head($4);
966                 if($3)
967                 {
968                         $$->lvc = *($3);
969                         free($3);
970                 }
971                 if(!$$->lvc.language)
972                         $$->lvc.language = dup_language(currentlanguage);
973                 }
974         ;
975
976 menu_body
977         : tBEGIN item_definitions tEND  { $$ = $2; }
978         ;
979
980 item_definitions
981         : /* Empty */   {$$ = NULL;}
982         | item_definitions MENUITEM tSTRING ',' expr item_options {
983                 $$=new_menu_item();
984                 $$->prev = $1;
985                 if($1)
986                         $1->next = $$;
987                 $$->id =  $5;
988                 $$->state = $6;
989                 $$->name = $3;
990                 }
991         | item_definitions MENUITEM SEPARATOR {
992                 $$=new_menu_item();
993                 $$->prev = $1;
994                 if($1)
995                         $1->next = $$;
996                 }
997         | item_definitions POPUP tSTRING item_options menu_body {
998                 $$ = new_menu_item();
999                 $$->prev = $1;
1000                 if($1)
1001                         $1->next = $$;
1002                 $$->popup = get_item_head($5);
1003                 $$->name = $3;
1004                 }
1005         ;
1006
1007 /* NOTE: item_options is right recursive because it would introduce
1008  * a shift/reduce conflict on ',' in itemex_options due to the
1009  * empty rule here. The parser is now forced to look beyond the ','
1010  * before reducing (force shift).
1011  * Right recursion here is not a problem because we cannot expect
1012  * more than 7 parserstack places to be occupied while parsing this
1013  * (who would want to specify a MF_x flag twice?).
1014  */
1015 item_options
1016         : /* Empty */                   { $$ = 0; }
1017         | ',' CHECKED   item_options    { $$ = $3 | MF_CHECKED; }
1018         | ',' GRAYED    item_options    { $$ = $3 | MF_GRAYED; }
1019         | ',' HELP      item_options    { $$ = $3 | MF_HELP; }
1020         | ',' INACTIVE  item_options    { $$ = $3 | MF_DISABLED; }
1021         | ',' MENUBARBREAK item_options { $$ = $3 | MF_MENUBARBREAK; }
1022         | ',' MENUBREAK item_options    { $$ = $3 | MF_MENUBREAK; }
1023         ;
1024
1025 /* ------------------------------ MenuEx ------------------------------ */
1026 menuex  : MENUEX loadmemopts opt_lvc menuex_body        {
1027                 if(!win32)
1028                         yywarning("MENUEX not supported in 16-bit mode");
1029                 if(!$4)
1030                         yyerror("MenuEx must contain items");
1031                 $$ = new_menuex();
1032                 if($2)
1033                 {
1034                         $$->memopt = *($2);
1035                         free($2);
1036                 }
1037                 else
1038                         $$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
1039                 $$->items = get_itemex_head($4);
1040                 if($3)
1041                 {
1042                         $$->lvc = *($3);
1043                         free($3);
1044                 }
1045                 if(!$$->lvc.language)
1046                         $$->lvc.language = dup_language(currentlanguage);
1047                 }
1048         ;
1049
1050 menuex_body
1051         : tBEGIN itemex_definitions tEND { $$ = $2; }
1052         ;
1053
1054 itemex_definitions
1055         : /* Empty */   {$$ = NULL; }
1056         | itemex_definitions MENUITEM tSTRING itemex_options {
1057                 $$ = new_menuex_item();
1058                 $$->prev = $1;
1059                 if($1)
1060                         $1->next = $$;
1061                 $$->name = $3;
1062                 $$->id = $4->id;
1063                 $$->type = $4->type;
1064                 $$->state = $4->state;
1065                 $$->helpid = $4->helpid;
1066                 $$->gotid = $4->gotid;
1067                 $$->gottype = $4->gottype;
1068                 $$->gotstate = $4->gotstate;
1069                 $$->gothelpid = $4->gothelpid;
1070                 free($4);
1071                 }
1072         | itemex_definitions MENUITEM SEPARATOR {
1073                 $$ = new_menuex_item();
1074                 $$->prev = $1;
1075                 if($1)
1076                         $1->next = $$;
1077                 }
1078         | itemex_definitions POPUP tSTRING itemex_p_options menuex_body {
1079                 $$ = new_menuex_item();
1080                 $$->prev = $1;
1081                 if($1)
1082                         $1->next = $$;
1083                 $$->popup = get_itemex_head($5);
1084                 $$->name = $3;
1085                 $$->id = $4->id;
1086                 $$->type = $4->type;
1087                 $$->state = $4->state;
1088                 $$->helpid = $4->helpid;
1089                 $$->gotid = $4->gotid;
1090                 $$->gottype = $4->gottype;
1091                 $$->gotstate = $4->gotstate;
1092                 $$->gothelpid = $4->gothelpid;
1093                 free($4);
1094                 }
1095         ;
1096
1097 itemex_options
1098         : /* Empty */                   { $$ = new_itemex_opt(0, 0, 0, 0); }
1099         | ',' expr {
1100                 $$ = new_itemex_opt($2, 0, 0, 0);
1101                 $$->gotid = TRUE;
1102                 }
1103         | ',' e_expr ',' e_expr item_options {
1104                 $$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $5, 0);
1105                 $$->gotid = TRUE;
1106                 $$->gottype = TRUE;
1107                 $$->gotstate = TRUE;
1108                 if($2) free($2);
1109                 if($4) free($4);
1110                 }
1111         | ',' e_expr ',' e_expr ',' expr {
1112                 $$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $6, 0);
1113                 $$->gotid = TRUE;
1114                 $$->gottype = TRUE;
1115                 $$->gotstate = TRUE;
1116                 if($2) free($2);
1117                 if($4) free($4);
1118                 }
1119         ;
1120
1121 itemex_p_options
1122         : /* Empty */                   { $$ = new_itemex_opt(0, 0, 0, 0); }
1123         | ',' expr {
1124                 $$ = new_itemex_opt($2, 0, 0, 0);
1125                 $$->gotid = TRUE;
1126                 }
1127         | ',' e_expr ',' expr {
1128                 $$ = new_itemex_opt($2 ? *($2) : 0, $4, 0, 0);
1129                 if($2) free($2);
1130                 $$->gotid = TRUE;
1131                 $$->gottype = TRUE;
1132                 }
1133         | ',' e_expr ',' e_expr ',' expr {
1134                 $$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $6, 0);
1135                 if($2) free($2);
1136                 if($4) free($4);
1137                 $$->gotid = TRUE;
1138                 $$->gottype = TRUE;
1139                 $$->gotstate = TRUE;
1140                 }
1141         | ',' e_expr ',' e_expr ',' e_expr ',' expr {
1142                 $$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $6 ? *($6) : 0, $8);
1143                 if($2) free($2);
1144                 if($4) free($4);
1145                 if($6) free($6);
1146                 $$->gotid = TRUE;
1147                 $$->gottype = TRUE;
1148                 $$->gotstate = TRUE;
1149                 $$->gothelpid = TRUE;
1150                 }
1151         ;
1152
1153 /* ------------------------------ StringTable ------------------------------ */
1154 /* Stringtables are parsed differently than other resources because their
1155  * layout is substantially different from other resources.
1156  * The table is parsed through a _global_ variable 'tagstt' which holds the
1157  * current stringtable descriptor (stringtable_t *) and 'sttres' that holds a
1158  * list of stringtables of different languages.
1159  */
1160 stringtable
1161         : stt_head tBEGIN strings tEND {
1162                 if(!$3)
1163                 {
1164                         yyerror("Stringtable must have at least one entry");
1165                 }
1166                 else
1167                 {
1168                         stringtable_t *stt;
1169                         /* Check if we added to a language table or created
1170                          * a new one.
1171                          */
1172                          for(stt = sttres; stt; stt = stt->next)
1173                          {
1174                                 if(stt == tagstt)
1175                                         break;
1176                          }
1177                          if(!stt)
1178                          {
1179                                 /* It is a new one */
1180                                 if(sttres)
1181                                 {
1182                                         sttres->prev = tagstt;
1183                                         tagstt->next = sttres;
1184                                         sttres = tagstt;
1185                                 }
1186                                 else
1187                                         sttres = tagstt;
1188                          }
1189                          /* Else were done */
1190                 }
1191                 if(tagstt_memopt)
1192                 {
1193                         free(tagstt_memopt);
1194                         tagstt_memopt = NULL;
1195                 }
1196
1197                 $$ = tagstt;
1198                 }
1199         ;
1200
1201 /* This is to get the language of the currently parsed stringtable */
1202 stt_head: STRINGTABLE loadmemopts opt_lvc {
1203                 if((tagstt = find_stringtable($3)) == NULL)
1204                         tagstt = new_stringtable($3);
1205                 tagstt_memopt = $2;
1206                 tagstt_version = $3->version;
1207                 tagstt_characts = $3->characts;
1208                 if($3)
1209                         free($3);
1210                 }
1211         ;
1212
1213 strings : /* Empty */   { $$ = NULL; }
1214         | strings expr opt_comma tSTRING {
1215                 int i;
1216                 assert(tagstt != NULL);
1217                 /* Search for the ID */
1218                 for(i = 0; i < tagstt->nentries; i++)
1219                 {
1220                         if(tagstt->entries[i].id == $2)
1221                                 yyerror("Stringtable ID %d already in use", $2);
1222                 }
1223                 /* If we get here, then we have a new unique entry */
1224                 tagstt->nentries++;
1225                 tagstt->entries = xrealloc(tagstt->entries, sizeof(tagstt->entries[0]) * tagstt->nentries);
1226                 tagstt->entries[tagstt->nentries-1].id = $2;
1227                 tagstt->entries[tagstt->nentries-1].str = $4;
1228                 if(tagstt_memopt)
1229                         tagstt->entries[tagstt->nentries-1].memopt = *tagstt_memopt;
1230                 else
1231                         tagstt->entries[tagstt->nentries-1].memopt = WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE;
1232                 tagstt->entries[tagstt->nentries-1].version = tagstt_version;
1233                 tagstt->entries[tagstt->nentries-1].characts = tagstt_characts;
1234
1235                 if(!win32 && $4->size > 254)
1236                         yyerror("Stringtable entry more than 254 characters");
1237                 if(win32 && $4->size > 65534) /* Hmm..., does this happen? */
1238                         yyerror("Stringtable entry more than 65534 characters (probably something else that went wrong)");
1239                 $$ = tagstt;
1240                 }
1241         ;
1242
1243 opt_comma       /* There seem to be two ways to specify a stringtable... */
1244         : /* Empty */
1245         | ','
1246         ;
1247
1248 /* ------------------------------ VersionInfo ------------------------------ */
1249 versioninfo
1250         : VERSIONINFO fix_version tBEGIN ver_blocks tEND {
1251                 $$ = $2;
1252                 $2->blocks = get_ver_block_head($4);
1253                 }
1254         ;
1255
1256 fix_version
1257         : /* Empty */                   { $$ = new_versioninfo(); }
1258         | fix_version FILEVERSION expr ',' expr ',' expr ',' expr {
1259                 if($1->gotit.fv)
1260                         yyerror("FILEVERSION already defined");
1261                 $$ = $1;
1262                 $$->filever_maj1 = $3;
1263                 $$->filever_maj2 = $5;
1264                 $$->filever_min1 = $7;
1265                 $$->filever_min2 = $9;
1266                 $$->gotit.fv = 1;
1267                 }
1268         | fix_version PRODUCTVERSION expr ',' expr ',' expr ',' expr {
1269                 if($1->gotit.pv)
1270                         yyerror("PRODUCTVERSION already defined");
1271                 $$ = $1;
1272                 $$->prodver_maj1 = $3;
1273                 $$->prodver_maj2 = $5;
1274                 $$->prodver_min1 = $7;
1275                 $$->prodver_min2 = $9;
1276                 $$->gotit.pv = 1;
1277                 }
1278         | fix_version FILEFLAGS expr {
1279                 if($1->gotit.ff)
1280                         yyerror("FILEFLAGS already defined");
1281                 $$ = $1;
1282                 $$->fileflags = $3;
1283                 $$->gotit.ff = 1;
1284                 }
1285         | fix_version FILEFLAGSMASK expr {
1286                 if($1->gotit.ffm)
1287                         yyerror("FILEFLAGSMASK already defined");
1288                 $$ = $1;
1289                 $$->fileflagsmask = $3;
1290                 $$->gotit.ffm = 1;
1291                 }
1292         | fix_version FILEOS expr {
1293                 if($1->gotit.fo)
1294                         yyerror("FILEOS already defined");
1295                 $$ = $1;
1296                 $$->fileos = $3;
1297                 $$->gotit.fo = 1;
1298                 }
1299         | fix_version FILETYPE expr {
1300                 if($1->gotit.ft)
1301                         yyerror("FILETYPE already defined");
1302                 $$ = $1;
1303                 $$->filetype = $3;
1304                 $$->gotit.ft = 1;
1305                 }
1306         | fix_version FILESUBTYPE expr {
1307                 if($1->gotit.fst)
1308                         yyerror("FILESUBTYPE already defined");
1309                 $$ = $1;
1310                 $$->filesubtype = $3;
1311                 $$->gotit.fst = 1;
1312                 }
1313         ;
1314
1315 ver_blocks
1316         : /* Empty */                   { $$ = NULL; }
1317         | ver_blocks ver_block {
1318                 $$ = $2;
1319                 $$->prev = $1;
1320                 if($1)
1321                         $1->next = $$;
1322                 }
1323         ;
1324
1325 ver_block
1326         : BLOCK tSTRING tBEGIN ver_values tEND {
1327                 $$ = new_ver_block();
1328                 $$->name = $2;
1329                 $$->values = get_ver_value_head($4);
1330                 }
1331         ;
1332
1333 ver_values
1334         : /* Empty */                   { $$ = NULL; }
1335         | ver_values ver_value {
1336                 $$ = $2;
1337                 $$->prev = $1;
1338                 if($1)
1339                         $1->next = $$;
1340                 }
1341         ;
1342
1343 ver_value
1344         : ver_block {
1345                 $$ = new_ver_value();
1346                 $$->type = val_block;
1347                 $$->value.block = $1;
1348                 }
1349         | VALUE tSTRING ',' tSTRING {
1350                 $$ = new_ver_value();
1351                 $$->type = val_str;
1352                 $$->key = $2;
1353                 $$->value.str = $4;
1354                 }
1355         | VALUE tSTRING ',' ver_words {
1356                 $$ = new_ver_value();
1357                 $$->type = val_words;
1358                 $$->key = $2;
1359                 $$->value.words = $4;
1360                 }
1361         ;
1362
1363 ver_words
1364         : expr                  { $$ = new_ver_words($1); }
1365         | ver_words ',' expr    { $$ = add_ver_words($1, $3); }
1366         ;
1367
1368 /* ------------------------------ Memory options ------------------------------ */
1369 loadmemopts
1370         : /* Empty */           { $$ = NULL; }
1371         | loadmemopts lamo {
1372                 if($1)
1373                 {
1374                         *($1) |= *($2);
1375                         $$ = $1;
1376                         free($2);
1377                 }
1378                 else
1379                         $$ = $2;
1380                 }
1381         | loadmemopts lama {
1382                 if($1)
1383                 {
1384                         *($1) &= *($2);
1385                         $$ = $1;
1386                         free($2);
1387                 }
1388                 else
1389                 {
1390                         *$2 &= WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE;
1391                         $$ = $2;
1392                 }
1393                 }
1394         ;
1395
1396 lamo    : PRELOAD       { $$ = new_int(WRC_MO_PRELOAD); }
1397         | MOVEABLE      { $$ = new_int(WRC_MO_MOVEABLE); }
1398         | DISCARDABLE   { $$ = new_int(WRC_MO_DISCARDABLE); }
1399         | tPURE         { $$ = new_int(WRC_MO_PURE); }
1400         ;
1401
1402 lama    : LOADONCALL    { $$ = new_int(~WRC_MO_PRELOAD); }
1403         | tFIXED        { $$ = new_int(~WRC_MO_MOVEABLE); }
1404         | IMPURE        { $$ = new_int(~WRC_MO_PURE); }
1405         ;
1406
1407 /* ------------------------------ Win32 options ------------------------------ */
1408 opt_lvc : /* Empty */           { $$ = new_lvc(); }
1409         | opt_lvc opt_language {
1410                 if(!win32)
1411                         yywarning("LANGUAGE not supported in 16-bit mode");
1412                 if($1->language)
1413                         yyerror("Language already defined");
1414                 $$ = $1;
1415                 $1->language = $2;
1416                 }
1417         | opt_lvc opt_characts {
1418                 if(!win32)
1419                         yywarning("CHARACTERISTICS not supported in 16-bit mode");
1420                 if($1->characts)
1421                         yyerror("Characteristics already defined");
1422                 $$ = $1;
1423                 $1->characts = $2;
1424                 }
1425         | opt_lvc opt_version {
1426                 if(!win32)
1427                         yywarning("VERSION not supported in 16-bit mode");
1428                 if($1->version)
1429                         yyerror("Version already defined");
1430                 $$ = $1;
1431                 $1->version = $2;
1432                 }
1433         ;
1434
1435 opt_language
1436         : LANGUAGE expr ',' expr        { $$ = new_language($2, $4); }
1437         ;
1438
1439 opt_characts
1440         : CHARACTERISTICS expr          { $$ = new_characts($2); }
1441         ;
1442
1443 opt_version
1444         : VERSION expr                  { $$ = new_version($2); }
1445         ;
1446
1447 /* ------------------------------ Raw data handking ------------------------------ */
1448 raw_data: tBEGIN raw_elements tEND      { $$ = $2; }
1449         ;
1450
1451 raw_elements
1452         : RAWDATA                       { $$ = $1; }
1453         | NUMBER                        { $$ = int2raw_data($1); }
1454         | tSTRING                       { $$ = str2raw_data($1); }
1455         | raw_elements opt_comma RAWDATA   { $$ = merge_raw_data($1, $3); free($3->data); free($3); }
1456         | raw_elements opt_comma NUMBER    { $$ = merge_raw_data_int($1, $3); }
1457         | raw_elements opt_comma tSTRING   { $$ = merge_raw_data_str($1, $3); }
1458         ;
1459
1460 /* ------------------------------ Win32 expressions ------------------------------ */
1461 /* All win16 numbers are also handled here. This is inconsistent with MS'
1462  * resource compiler, but what the heck, its just handy to have.
1463  */
1464 e_expr  : /* Empty */   { $$ = 0; }
1465         | expr          { $$ = new_int($1); }
1466         ;
1467 expr    : dummy xpr     { $$ = ($2) & andmask; }
1468         ;
1469
1470 dummy   : /* Empty */   { $$ = 0; andmask = -1; }
1471         ;
1472
1473 xpr     : xpr '+' xpr   { $$ = ($1) + ($3); }
1474         | xpr '-' xpr   { $$ = ($1) - ($3); }
1475         | xpr '|' xpr   { $$ = ($1) | ($3); }
1476         | xpr '&' xpr   { $$ = ($1) & ($3); }
1477         | xpr '*' xpr   { $$ = ($1) * ($3); }
1478         | xpr '/' xpr   { $$ = ($1) / ($3); }
1479         | '~' xpr       { $$ = ~($2); }
1480         | '-' xpr       { $$ = -($2); }         /* FIXME: shift/reduce conflict */
1481 /*      | '+' xpr       { $$ = $2; } */
1482         | '(' xpr ')'   { $$ = $2; }
1483         | NUMBER        { $$ = $1; want_rscname = 0; }
1484         | NOT NUMBER    { $$ = 0; andmask &= ~($2); }
1485         ;
1486 %%
1487 /* Dialog specific functions */
1488 dialog_t *dialog_style(int st, dialog_t *dlg)
1489 {
1490         DWORD s = 0;
1491         assert(dlg != NULL);
1492         if(dlg->gotstyle)
1493         {
1494                 yywarning("Style already defined, or-ing together");
1495                 s = dlg->style;
1496         }
1497         dlg->style = st | s;
1498         dlg->gotstyle = TRUE;
1499         return dlg;
1500 }
1501
1502 dialog_t *dialog_exstyle(int st, dialog_t *dlg)
1503 {
1504         DWORD s = 0;
1505         assert(dlg != NULL);
1506         if(dlg->gotexstyle)
1507         {
1508                 yywarning("ExStyle already defined, or-ing together");
1509                 s = dlg->style;
1510         }
1511         dlg->exstyle = st | s;
1512         dlg->gotexstyle = TRUE;
1513         return dlg;
1514 }
1515
1516 dialog_t *dialog_caption(string_t *s, dialog_t *dlg)
1517 {
1518         assert(dlg != NULL);
1519         if(dlg->title)
1520                 yyerror("Caption already defined");
1521         dlg->title = s;
1522         return dlg;
1523 }
1524
1525 dialog_t *dialog_font(font_id_t *f, dialog_t *dlg)
1526 {
1527         assert(dlg != NULL);
1528         if(dlg->font)
1529                 yyerror("Font already defined");
1530         dlg->font = f;
1531         return dlg;
1532 }
1533
1534 dialog_t *dialog_class(name_id_t *n, dialog_t *dlg)
1535 {
1536         assert(dlg != NULL);
1537         if(dlg->dlgclass)
1538                 yyerror("Class already defined");
1539         dlg->dlgclass = n;
1540         return dlg;
1541 }
1542
1543 dialog_t *dialog_menu(name_id_t *m, dialog_t *dlg)
1544 {
1545         assert(dlg != NULL);
1546         if(dlg->menu)
1547                 yyerror("Menu already defined");
1548         dlg->menu = m;
1549         return dlg;
1550 }
1551
1552 dialog_t *dialog_language(language_t *l, dialog_t *dlg)
1553 {
1554         assert(dlg != NULL);
1555         if(dlg->lvc.language)
1556                 yyerror("Language already defined");
1557         dlg->lvc.language = l;
1558         return dlg;
1559 }
1560
1561 dialog_t *dialog_characteristics(characts_t *c, dialog_t *dlg)
1562 {
1563         assert(dlg != NULL);
1564         if(dlg->lvc.characts)
1565                 yyerror("Characteristics already defined");
1566         dlg->lvc.characts = c;
1567         return dlg;
1568 }
1569
1570 dialog_t *dialog_version(version_t *v, dialog_t *dlg)
1571 {
1572         assert(dlg != NULL);
1573         if(dlg->lvc.version)
1574                 yyerror("Version already defined");
1575         dlg->lvc.version = v;
1576         return dlg;
1577 }
1578
1579 /* Controls specific functions */
1580 control_t *ins_ctrl(int type, int style, control_t *ctrl, control_t *prev)
1581 {
1582         assert(ctrl != NULL);
1583         ctrl->prev = prev;
1584         if(prev)
1585                 prev->next = ctrl;
1586         if(type != -1)
1587         {
1588                 ctrl->ctlclass = new_name_id();
1589                 ctrl->ctlclass->type = name_ord;
1590                 ctrl->ctlclass->name.i_name = type;
1591         }
1592
1593         /* Hm... this seems to be jammed in at all time... */
1594         ctrl->style |= WS_CHILD | WS_VISIBLE;
1595         switch(type)
1596         {
1597         case CT_BUTTON:
1598                 ctrl->style |= style;
1599                 if(style != BS_GROUPBOX && style != BS_RADIOBUTTON)
1600                         ctrl->style |= WS_TABSTOP;
1601                 break;
1602         case CT_EDIT:
1603                 ctrl->style |= WS_TABSTOP | WS_BORDER;
1604                 break;
1605         case CT_LISTBOX:
1606                 ctrl->style |= LBS_NOTIFY | WS_BORDER;
1607                 break;
1608         case CT_COMBOBOX:
1609                 ctrl->style |= CBS_SIMPLE;
1610                 break;
1611         case CT_STATIC:
1612                 ctrl->style |= style;
1613                 if(style == SS_CENTER || style == SS_LEFT || style == SS_RIGHT)
1614                         ctrl->style |= WS_GROUP;
1615                 break;
1616         }
1617
1618         if(!ctrl->gotstyle)     /* Handle default style setting */
1619         {
1620                 switch(type)
1621                 {
1622                 case CT_EDIT:
1623                         ctrl->style |= ES_LEFT;
1624                         break;
1625                 case CT_LISTBOX:
1626                         ctrl->style |= LBS_NOTIFY;
1627                         break;
1628                 case CT_COMBOBOX:
1629                         ctrl->style |= CBS_SIMPLE | WS_TABSTOP;
1630                         break;
1631                 case CT_SCROLLBAR:
1632                         ctrl->style |= SBS_HORZ;
1633                         break;
1634                 case CT_BUTTON:
1635                         switch(style)
1636                         {
1637                         case BS_CHECKBOX:
1638                         case BS_DEFPUSHBUTTON:
1639                         case BS_PUSHBUTTON:
1640                         case BS_GROUPBOX:
1641 /*                      case BS_PUSHBOX:        */
1642                         case BS_AUTORADIOBUTTON:
1643                         case BS_AUTO3STATE:
1644                         case BS_3STATE:
1645                         case BS_AUTOCHECKBOX:
1646                                 ctrl->style |= WS_TABSTOP;
1647                                 break;
1648                         default:
1649                                 yywarning("Unknown default button control-style 0x%08x", style);
1650                         case BS_RADIOBUTTON:
1651                                 break;
1652                         }
1653                         break;
1654
1655                 case CT_STATIC:
1656                         switch(style)
1657                         {
1658                         case SS_LEFT:
1659                         case SS_RIGHT:
1660                         case SS_CENTER:
1661                                 ctrl->style |= WS_GROUP;
1662                                 break;
1663                         case SS_ICON:   /* Special case */
1664                                 break;
1665                         default:
1666                                 yywarning("Unknown default static control-style 0x%08x", style);
1667                                 break;
1668                         }
1669                         break;
1670                 case -1:        /* Generic control */
1671                         goto byebye;
1672
1673                 default:
1674                         yyerror("Internal error (report this): Got weird control type 0x%08x", type);
1675                 }
1676         }
1677
1678         /* The SS_ICON flag is always forced in for icon controls */
1679         if(type == CT_STATIC && style == SS_ICON)
1680                 ctrl->style |= SS_ICON;
1681
1682         ctrl->gotstyle = TRUE;
1683 byebye:
1684         return ctrl;
1685 }
1686
1687 name_id_t *convert_ctlclass(name_id_t *cls)
1688 {
1689         char *cc;
1690         int iclass;
1691
1692         if(cls->type == name_ord)
1693                 return cls;
1694         assert(cls->type == name_str);
1695         if(cls->type == str_unicode)
1696         {
1697                 yyerror("Don't yet support unicode class comparison");
1698         }
1699         else
1700                 cc = cls->name.s_name->str.cstr;
1701
1702         if(!stricmp("BUTTON", cc))
1703                 iclass = CT_BUTTON;
1704         else if(!stricmp("COMBOBOX", cc))
1705                 iclass = CT_COMBOBOX;
1706         else if(!stricmp("LISTBOX", cc))
1707                 iclass = CT_LISTBOX;
1708         else if(!stricmp("EDIT", cc))
1709                 iclass = CT_EDIT;
1710         else if(!stricmp("STATIC", cc))
1711                 iclass = CT_STATIC;
1712         else if(!stricmp("SCROLLBAR", cc))
1713                 iclass = CT_SCROLLBAR;
1714         else
1715                 return cls;     /* No default, return user controlclass */
1716
1717         free(cls->name.s_name->str.cstr);
1718         free(cls->name.s_name);
1719         cls->type = name_ord;
1720         cls->name.i_name = iclass;
1721         return cls;
1722 }
1723
1724 /* DialogEx specific functions */
1725 dialogex_t *dialogex_style(int st, dialogex_t *dlg)
1726 {
1727         DWORD s = 0;
1728         assert(dlg != NULL);
1729         if(dlg->gotstyle)
1730         {
1731                 yywarning("Style already defined, or-ing together");
1732                 s = dlg->style;
1733         }
1734         dlg->style = st | s;
1735         dlg->gotstyle = TRUE;
1736         return dlg;
1737 }
1738
1739 dialogex_t *dialogex_exstyle(int st, dialogex_t *dlg)
1740 {
1741         DWORD s = 0;
1742         assert(dlg != NULL);
1743         if(dlg->gotexstyle)
1744         {
1745                 yywarning("ExStyle already defined, or-ing together");
1746                 s = dlg->exstyle;
1747         }
1748         dlg->exstyle = st | s;
1749         dlg->gotexstyle = TRUE;
1750         return dlg;
1751 }
1752
1753 dialogex_t *dialogex_caption(string_t *s, dialogex_t *dlg)
1754 {
1755         assert(dlg != NULL);
1756         if(dlg->title)
1757                 yyerror("Caption already defined");
1758         dlg->title = s;
1759         return dlg;
1760 }
1761
1762 dialogex_t *dialogex_font(font_id_t *f, dialogex_t *dlg)
1763 {
1764         assert(dlg != NULL);
1765         if(dlg->font)
1766                 yyerror("Font already defined");
1767         dlg->font = f;
1768         return dlg;
1769 }
1770
1771 dialogex_t *dialogex_class(name_id_t *n, dialogex_t *dlg)
1772 {
1773         assert(dlg != NULL);
1774         if(dlg->dlgclass)
1775                 yyerror("Class already defined");
1776         dlg->dlgclass = n;
1777         return dlg;
1778 }
1779
1780 dialogex_t *dialogex_menu(name_id_t *m, dialogex_t *dlg)
1781 {
1782         assert(dlg != NULL);
1783         if(dlg->menu)
1784                 yyerror("Menu already defined");
1785         dlg->menu = m;
1786         return dlg;
1787 }
1788
1789 dialogex_t *dialogex_language(language_t *l, dialogex_t *dlg)
1790 {
1791         assert(dlg != NULL);
1792         if(dlg->lvc.language)
1793                 yyerror("Language already defined");
1794         dlg->lvc.language = l;
1795         return dlg;
1796 }
1797
1798 dialogex_t *dialogex_characteristics(characts_t *c, dialogex_t *dlg)
1799 {
1800         assert(dlg != NULL);
1801         if(dlg->lvc.characts)
1802                 yyerror("Characteristics already defined");
1803         dlg->lvc.characts = c;
1804         return dlg;
1805 }
1806
1807 dialogex_t *dialogex_version(version_t *v, dialogex_t *dlg)
1808 {
1809         assert(dlg != NULL);
1810         if(dlg->lvc.version)
1811                 yyerror("Version already defined");
1812         dlg->lvc.version = v;
1813         return dlg;
1814 }
1815
1816 /* Accelerator specific functions */
1817 event_t *add_event(int key, int id, int flags, event_t *prev)
1818 {
1819         event_t *ev = new_event();
1820
1821         if((flags & (WRC_AF_VIRTKEY | WRC_AF_ASCII)) == (WRC_AF_VIRTKEY | WRC_AF_ASCII))
1822                 yyerror("Cannot use both ASCII and VIRTKEY");
1823
1824         ev->key = key;
1825         ev->id = id;
1826         ev->flags = flags & ~WRC_AF_ASCII;
1827         ev->prev = prev;
1828         if(prev)
1829                 prev->next = ev;
1830         return ev;
1831 }
1832
1833 event_t *add_string_event(string_t *key, int id, int flags, event_t *prev)
1834 {
1835         int keycode;
1836         event_t *ev = new_event();
1837
1838         if(key->type != str_char)
1839                 yyerror("Key code must be an ascii string");
1840
1841         if((flags & WRC_AF_VIRTKEY) && (!isupper(key->str.cstr[0]) || !isdigit(key->str.cstr[0])))
1842                 yyerror("VIRTKEY code is not equal to ascii value");
1843
1844         if(key->str.cstr[0] == '^')
1845         {
1846                 keycode = toupper(key->str.cstr[1]) - '@';
1847                 if(keycode >= ' ')
1848                         yyerror("Control-code out of range");
1849         }
1850         else
1851                 keycode = key->str.cstr[0];
1852         ev->key = keycode;
1853         ev->id = id;
1854         ev->flags = flags & ~WRC_AF_ASCII;
1855         ev->prev = prev;
1856         if(prev)
1857                 prev->next = ev;
1858         return ev;
1859 }
1860
1861 /* MenuEx specific functions */
1862 itemex_opt_t *new_itemex_opt(int id, int type, int state, int helpid)
1863 {
1864         itemex_opt_t *opt = (itemex_opt_t *)xmalloc(sizeof(itemex_opt_t));
1865         opt->id = id;
1866         opt->type = type;
1867         opt->state = state;
1868         opt->helpid = helpid;
1869         return opt;
1870 }
1871
1872 /* Raw data functions */
1873 raw_data_t *load_file(string_t *name)
1874 {
1875         FILE *fp;
1876         raw_data_t *rd;
1877         if(name->type != str_char)
1878                 yyerror("Filename must be ASCII string");
1879                 
1880         fp = fopen(name->str.cstr, "rb");
1881         if(!fp)
1882                 yyerror("Cannot open file %s", name);
1883         rd = new_raw_data();
1884         fseek(fp, 0, SEEK_END);
1885         rd->size = ftell(fp);
1886         fseek(fp, 0, SEEK_SET);
1887         rd->data = (char *)xmalloc(rd->size);
1888         fread(rd->data, rd->size, 1, fp);
1889         fclose(fp);
1890         HEAPCHECK();
1891         return rd;
1892 }
1893
1894 raw_data_t *int2raw_data(int i)
1895 {
1896         raw_data_t *rd;
1897         rd = new_raw_data();
1898         rd->size = sizeof(short);
1899         rd->data = (char *)xmalloc(rd->size);
1900         *(short *)(rd->data) = (short)i;
1901         return rd;
1902 }
1903
1904 raw_data_t *str2raw_data(string_t *str)
1905 {
1906         raw_data_t *rd;
1907         rd = new_raw_data();
1908         rd->size = str->size * (str->type == str_char ? 1 : 2);
1909         rd->data = (char *)xmalloc(rd->size);
1910         memcpy(rd->data, str->str.cstr, rd->size);
1911         return rd;
1912 }
1913
1914 raw_data_t *merge_raw_data(raw_data_t *r1, raw_data_t *r2)
1915 {
1916         r1->data = xrealloc(r1->data, r1->size + r2->size);
1917         memcpy(r1->data + r1->size, r2->data, r2->size);
1918         r1->size += r2->size;
1919         return r1;
1920 }
1921
1922 raw_data_t *merge_raw_data_int(raw_data_t *r1, int i)
1923 {
1924         raw_data_t *t = int2raw_data(i);
1925         merge_raw_data(r1, t);
1926         free(t->data);
1927         free(t);
1928         return r1;
1929 }
1930
1931 raw_data_t *merge_raw_data_str(raw_data_t *r1, string_t *str)
1932 {
1933         raw_data_t *t = str2raw_data(str);
1934         merge_raw_data(r1, t);
1935         free(t->data);
1936         free(t);
1937         return r1;
1938 }
1939
1940 /* Function the go back in a list to get the head */
1941 menu_item_t *get_item_head(menu_item_t *p)
1942 {
1943         if(!p)
1944                 return NULL;
1945         while(p->prev)
1946                 p = p->prev;
1947         return p;
1948 }
1949
1950 menuex_item_t *get_itemex_head(menuex_item_t *p)
1951 {
1952         if(!p)
1953                 return NULL;
1954         while(p->prev)
1955                 p = p->prev;
1956         return p;
1957 }
1958
1959 resource_t *get_resource_head(resource_t *p)
1960 {
1961         if(!p)
1962                 return NULL;
1963         while(p->prev)
1964                 p = p->prev;
1965         return p;
1966 }
1967
1968 ver_block_t *get_ver_block_head(ver_block_t *p)
1969 {
1970         if(!p)
1971                 return NULL;
1972         while(p->prev)
1973                 p = p->prev;
1974         return p;
1975 }
1976
1977 ver_value_t *get_ver_value_head(ver_value_t *p)
1978 {
1979         if(!p)
1980                 return NULL;
1981         while(p->prev)
1982                 p = p->prev;
1983         return p;
1984 }
1985
1986 control_t *get_control_head(control_t *p)
1987 {
1988         if(!p)
1989                 return NULL;
1990         while(p->prev)
1991                 p = p->prev;
1992         return p;
1993 }
1994
1995 event_t *get_event_head(event_t *p)
1996 {
1997         if(!p)
1998                 return NULL;
1999         while(p->prev)
2000                 p = p->prev;
2001         return p;
2002 }
2003
2004 /* Find a stringtable with given language */
2005 stringtable_t *find_stringtable(lvc_t *lvc)
2006 {
2007         stringtable_t *stt;
2008
2009         assert(lvc != NULL);
2010
2011         if(!lvc->language)
2012                 lvc->language = currentlanguage;
2013
2014         for(stt = sttres; stt; stt = stt->next)
2015         {
2016                 if(stt->lvc.language->id == lvc->language->id
2017                 && stt->lvc.language->id == lvc->language->id)
2018                 {
2019                         /* Found a table with the same language */
2020                         /* The version and characteristics are now handled
2021                          * in the generation of the individual stringtables.
2022                          * This enables localized analysis.
2023                         if((stt->lvc.version && lvc->version && *(stt->lvc.version) != *(lvc->version))
2024                         || (!stt->lvc.version && lvc->version)
2025                         || (stt->lvc.version && !lvc->version))
2026                                 yywarning("Stringtable's versions are not the same, using first definition");
2027
2028                         if((stt->lvc.characts && lvc->characts && *(stt->lvc.characts) != *(lvc->characts))
2029                         || (!stt->lvc.characts && lvc->characts)
2030                         || (stt->lvc.characts && !lvc->characts))
2031                                 yywarning("Stringtable's characteristics are not the same, using first definition");
2032                         */
2033                         return stt;
2034                 }
2035         }
2036         return NULL;
2037 }
2038
2039 /* qsort sorting function for string table entries */
2040 #define STE(p)  ((stt_entry_t *)(p))
2041 int sort_stt_entry(const void *e1, const void *e2)
2042 {
2043         return STE(e1)->id - STE(e2)->id;
2044 }
2045 #undef STE
2046
2047 resource_t *build_stt_resources(stringtable_t *stthead)
2048 {
2049         stringtable_t *stt;
2050         stringtable_t *newstt;
2051         resource_t *rsc;
2052         resource_t *rsclist = NULL;
2053         resource_t *rsctail = NULL;
2054         int i;
2055         int j;
2056         DWORD andsum;
2057         DWORD orsum;
2058         characts_t *characts;
2059         version_t *version;
2060
2061         if(!stthead)
2062                 return NULL;
2063
2064         /* For all languages defined */
2065         for(stt = stthead; stt; stt = stt->next)
2066         {
2067                 assert(stt->nentries > 0);
2068
2069                 /* Sort the entries */
2070                 if(stt->nentries > 1)
2071                         qsort(stt->entries, stt->nentries, sizeof(stt->entries[0]), sort_stt_entry);
2072
2073                 for(i = 0; i < stt->nentries; )
2074                 {
2075                         newstt = new_stringtable(&stt->lvc);
2076                         newstt->entries = (stt_entry_t *)xmalloc(16 * sizeof(stt_entry_t));
2077                         newstt->nentries = 16;
2078                         newstt->idbase = stt->entries[i].id & ~0xf;
2079                         for(j = 0; j < 16 && i < stt->nentries; j++)
2080                         {
2081                                 if(stt->entries[i].id - newstt->idbase == j)
2082                                 {
2083                                         newstt->entries[j] = stt->entries[i];
2084                                         i++;
2085                                 }
2086                         }
2087                         andsum = ~0;
2088                         orsum = 0;
2089                         characts = NULL;
2090                         version = NULL;
2091                         /* Check individual memory options and get
2092                          * the first characteristics/version
2093                          */
2094                         for(j = 0; j < 16; j++)
2095                         {
2096                                 if(!newstt->entries[j].str)
2097                                         continue;
2098                                 andsum &= newstt->entries[j].memopt;
2099                                 orsum |= newstt->entries[j].memopt;
2100                                 if(!characts)
2101                                         characts = newstt->entries[j].characts;
2102                                 if(!version)
2103                                         version = newstt->entries[j].version;
2104                         }
2105                         if(andsum != orsum)
2106                         {
2107                                 warning("Stringtable's memory options are not equal (idbase: %d)", newstt->idbase);
2108                         }
2109                         /* Check version and characteristics */
2110                         for(j = 0; j < 16; j++)
2111                         {
2112                                 if(characts
2113                                 && newstt->entries[j].characts
2114                                 && *newstt->entries[j].characts != *characts)
2115                                         warning("Stringtable's characteristics are not the same (idbase: %d)", newstt->idbase);
2116                                 if(version
2117                                 && newstt->entries[j].version
2118                                 && *newstt->entries[j].version != *version)
2119                                         warning("Stringtable's versions are not the same (idbase: %d)", newstt->idbase);
2120                         }
2121                         rsc = new_resource(res_stt, newstt, newstt->memopt, newstt->lvc.language);
2122                         rsc->name = new_name_id();
2123                         rsc->name->type = name_ord;
2124                         rsc->name->name.i_name = (newstt->idbase >> 4) + 1;
2125                         rsc->memopt = andsum; /* Set to least common denominator */
2126                         newstt->memopt = andsum;
2127                         newstt->lvc.characts = characts;
2128                         newstt->lvc.version = version;
2129                         if(!rsclist)
2130                         {
2131                                 rsclist = rsc;
2132                                 rsctail = rsc;
2133                         }
2134                         else
2135                         {
2136                                 rsctail->next = rsc;
2137                                 rsc->prev = rsctail;
2138                                 rsctail = rsc;
2139                         }
2140                 }
2141         }
2142         return rsclist;
2143 }
2144
2145 /* Cursor and icon splitter functions */
2146 int alloc_icon_id(void)
2147 {
2148         static int icon_id = 1;
2149         return icon_id++;
2150 }
2151
2152 int alloc_cursor_id(void)
2153 {
2154         static int cursor_id = 1;
2155         return cursor_id++;
2156 }
2157
2158 #define BPTR(base)      ((char *)(rd->data + (base)))
2159 #define WPTR(base)      ((WORD *)(rd->data + (base)))
2160 #define DPTR(base)      ((DWORD *)(rd->data + (base)))
2161 void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico)
2162 {
2163         int cnt;
2164         int i;
2165         icon_dir_entry_t *ide;
2166         icon_t *ico;
2167         icon_t *list = NULL;
2168
2169         /* FIXME: Distinguish between normal and animated icons (RIFF format) */
2170         if(WPTR(0)[1] != 1)
2171                 yyerror("Icon resource data has invalid type id %d", WPTR(0)[1]);
2172         cnt = WPTR(0)[2];
2173         ide = (icon_dir_entry_t *)&(WPTR(0)[3]);
2174         for(i = 0; i < cnt; i++)
2175         {
2176                 ico = new_icon();
2177                 ico->id = alloc_icon_id();
2178                 if(ide[i].offset > rd->size
2179                 || ide[i].offset + ide[i].ressize > rd->size)
2180                         yyerror("Icon resource data corrupt");
2181                 ico->width = ide[i].width;
2182                 ico->height = ide[i].height;
2183                 ico->nclr = ide[i].nclr;
2184                 ico->planes = ide[i].planes;
2185                 ico->bits = ide[i].bits;
2186                 if(!ico->planes)
2187                 {
2188                         /* Argh! They did not fill out the resdir structure */
2189                         ico->planes = ((BITMAPINFOHEADER *)BPTR(ide[i].offset))->biPlanes;
2190                 }
2191                 if(!ico->bits)
2192                 {
2193                         /* Argh! They did not fill out the resdir structure */
2194                         ico->bits = ((BITMAPINFOHEADER *)BPTR(ide[i].offset))->biBitCount;
2195                 }
2196                 ico->data = new_raw_data();
2197                 copy_raw_data(ico->data, rd, ide[i].offset, ide[i].ressize);
2198                 if(!list)
2199                 {
2200                         list = ico;
2201                 }
2202                 else
2203                 {
2204                         ico->next = list;
2205                         list->prev = ico;
2206                         list = ico;
2207                 }
2208         }
2209         icog->iconlist = list;
2210         *nico = cnt;
2211 }
2212
2213 void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur)
2214 {
2215         int cnt;
2216         int i;
2217         cursor_dir_entry_t *cde;
2218         cursor_t *cur;
2219         cursor_t *list = NULL;
2220
2221         /* FIXME: Distinguish between normal and animated cursors (RIFF format)*/
2222         if(WPTR(0)[1] != 2)
2223                 yyerror("Cursor resource data has invalid type id %d", WPTR(0)[1]);
2224         cnt = WPTR(0)[2];
2225         cde = (cursor_dir_entry_t *)&(WPTR(0)[3]);
2226         for(i = 0; i < cnt; i++)
2227         {
2228                 cur = new_cursor();
2229                 cur->id = alloc_cursor_id();
2230                 if(cde[i].offset > rd->size
2231                 || cde[i].offset + cde[i].ressize > rd->size)
2232                         yyerror("Cursor resource data corrupt");
2233                 cur->width = cde[i].width;
2234                 cur->height = cde[i].height;
2235                 cur->nclr = cde[i].nclr;
2236                 /* The next two are to support color cursors */
2237                 cur->planes = ((BITMAPINFOHEADER *)BPTR(cde[i].offset))->biPlanes;
2238                 cur->bits = ((BITMAPINFOHEADER *)BPTR(cde[i].offset))->biBitCount;
2239                 if(!win32 && (cur->planes != 1 || cur->bits != 1))
2240                         yywarning("Win16 cursor contains colors");
2241                 cur->xhot = cde[i].xhot;
2242                 cur->yhot = cde[i].yhot;
2243                 cur->data = new_raw_data();
2244                 copy_raw_data(cur->data, rd, cde[i].offset, cde[i].ressize);
2245                 if(!list)
2246                 {
2247                         list = cur;
2248                 }
2249                 else
2250                 {
2251                         cur->next = list;
2252                         list->prev = cur;
2253                         list = cur;
2254                 }
2255         }
2256         curg->cursorlist = list;
2257         *ncur = cnt;
2258 }
2259
2260 #undef  BPTR
2261 #undef  WPTR
2262 #undef  DPTR
2263
2264