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