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