Removed #include of wingdi.h and windef.h from winuser.h (and resolved
[wine.git] / tools / wrc / parser.y
blobfb0de3fde14f794e8eb5aa94dbac302c4810551f
1 %{
2 /*
3 * Copyright Martin von Loewis, 1994
4 * Copyright 1998 Bertho A. Stultiens (BS)
5 * 1999 Juergen Schmied (JS)
7 * 6-Nov-1999 JS - see CHANGES
8 *
9 * 29-Dec-1998 AdH - Grammar and function extensions.
10 * grammar: TOOLBAR resources, Named ICONs in
11 * DIALOGS
12 * functions: semantic actions for the grammar
13 * changes, resource files can now be anywhere
14 * on the include path instead of just in the
15 * current directory
17 * 20-Jun-1998 BS - Fixed a bug in load_file() where the name was not
18 * printed out correctly.
20 * 17-Jun-1998 BS - Fixed a bug in CLASS statement parsing which should
21 * also accept a tSTRING as argument.
23 * 25-May-1998 BS - Found out that I need to support language, version
24 * and characteristics in inline resources (bitmap,
25 * cursor, etc) but they can also be specified with
26 * a filename. This renders my filename-scanning scheme
27 * worthless. Need to build newline parsing to solve
28 * this one.
29 * It will come with version 1.1.0 (sigh).
31 * 19-May-1998 BS - Started to build a builtin preprocessor
33 * 30-Apr-1998 BS - Redid the stringtable parsing/handling. My previous
34 * ideas had some serious flaws.
36 * 27-Apr-1998 BS - Removed a lot of dead comments and put it in a doc
37 * file.
39 * 21-Apr-1998 BS - Added correct behavior for cursors and icons.
40 * - This file is growing too big. It is time to strip
41 * things and put it in a support file.
43 * 19-Apr-1998 BS - Tagged the stringtable resource so that only one
44 * resource will be created. This because the table
45 * has a different layout than other resources. The
46 * table has to be sorted, and divided into smaller
47 * resource entries (see comment in source).
49 * 17-Apr-1998 BS - Almost all strings, including identifiers, are parsed
50 * as string_t which include unicode strings upon
51 * input.
52 * - Parser now emits a warning when compiling win32
53 * extensions in win16 mode.
55 * 16-Apr-1998 BS - Raw data elements are now *optionally* seperated
56 * by commas. Read the comments in file sq2dq.l.
57 * - FIXME: there are instances in the source that rely
58 * on the fact that int==32bit and pointers are int size.
59 * - Fixed the conflict in menuex by changing a rule
60 * back into right recursion. See note in source.
61 * - UserType resources cannot have an expression as its
62 * typeclass. See note in source.
64 * 15-Apr-1998 BS - Changed all right recursion into left recursion to
65 * get reduction of the parsestack.
66 * This also helps communication between bison and flex.
67 * Main advantage is that the Empty rule gets reduced
68 * first, which is used to allocate/link things.
69 * It also added a shift/reduce conflict in the menuex
70 * handling, due to expression/option possibility,
71 * although not serious.
73 * 14-Apr-1998 BS - Redone almost the entire parser. We're not talking
74 * about making it more efficient, but readable (for me)
75 * and slightly easier to expand/change.
76 * This is done primarily by using more reduce states
77 * with many (intuitive) types for the various resource
78 * statements.
79 * - Added expression handling for all resources where a
80 * number is accepted (not only for win32). Also added
81 * multiply and division (not MS compatible, but handy).
82 * Unary minus introduced a shift/reduce conflict, but
83 * it is not serious.
85 * 13-Apr-1998 BS - Reordered a lot of things
86 * - Made the source more readable
87 * - Added Win32 resource definitions
88 * - Corrected syntax problems with an old yacc (;)
89 * - Added extra comment about grammar
91 #include "config.h"
93 #include <stdio.h>
94 #include <stdlib.h>
95 #include <stdarg.h>
96 #include <assert.h>
97 #include <ctype.h>
98 #include <string.h>
99 #ifdef HAVE_ALLOCA_H
100 #include <alloca.h>
101 #endif
103 #include "wrc.h"
104 #include "utils.h"
105 #include "newstruc.h"
106 #include "dumpres.h"
107 #include "preproc.h"
108 #include "parser.h"
109 #include "windef.h"
110 #include "wingdi.h"
111 #include "winuser.h"
113 #ifdef __BORLANDC__
114 #pragma warn -sig
115 #endif
117 int indialog = 0; /* Signal flex that we're parsing a dialog */
118 int want_rscname = 0; /* Set when a resource's name is required */
119 stringtable_t *tagstt; /* Stringtable tag.
120 * It is set while parsing a stringtable to one of
121 * the stringtables in the sttres list or a new one
122 * if the language was not parsed before.
124 stringtable_t *sttres; /* Stringtable resources. This holds the list of
125 * stringtables with different lanuages
127 /* Set to the current options of the currently scanning stringtable */
128 static int *tagstt_memopt;
129 static characts_t *tagstt_characts;
130 static version_t *tagstt_version;
132 /* Prototypes of here defined functions */
133 void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur);
134 void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico);
135 int alloc_cursor_id(language_t *);
136 int alloc_icon_id(language_t *);
137 void ins_stt_entry(stt_entry_t *ste);
138 int check_stt_entry(stringtable_t *tabs, stt_entry_t *ste);
139 event_t *get_event_head(event_t *p);
140 control_t *get_control_head(control_t *p);
141 ver_value_t *get_ver_value_head(ver_value_t *p);
142 ver_block_t *get_ver_block_head(ver_block_t *p);
143 resource_t *get_resource_head(resource_t *p);
144 menuex_item_t *get_itemex_head(menuex_item_t *p);
145 menu_item_t *get_item_head(menu_item_t *p);
146 raw_data_t *merge_raw_data_str(raw_data_t *r1, string_t *str);
147 raw_data_t *merge_raw_data_int(raw_data_t *r1, int i);
148 raw_data_t *merge_raw_data_long(raw_data_t *r1, int i);
149 raw_data_t *merge_raw_data(raw_data_t *r1, raw_data_t *r2);
150 raw_data_t *str2raw_data(string_t *str);
151 raw_data_t *int2raw_data(int i);
152 raw_data_t *long2raw_data(int i);
153 raw_data_t *load_file(string_t *name);
154 itemex_opt_t *new_itemex_opt(int id, int type, int state, int helpid);
155 event_t *add_string_event(string_t *key, int id, int flags, event_t *prev);
156 event_t *add_event(int key, int id, int flags, event_t *prev);
157 dialogex_t *dialogex_version(version_t *v, dialogex_t *dlg);
158 dialogex_t *dialogex_characteristics(characts_t *c, dialogex_t *dlg);
159 dialogex_t *dialogex_language(language_t *l, dialogex_t *dlg);
160 dialogex_t *dialogex_menu(name_id_t *m, dialogex_t *dlg);
161 dialogex_t *dialogex_class(name_id_t *n, dialogex_t *dlg);
162 dialogex_t *dialogex_font(font_id_t *f, dialogex_t *dlg);
163 dialogex_t *dialogex_caption(string_t *s, dialogex_t *dlg);
164 dialogex_t *dialogex_exstyle(style_t *st, dialogex_t *dlg);
165 dialogex_t *dialogex_style(style_t *st, dialogex_t *dlg);
166 name_id_t *convert_ctlclass(name_id_t *cls);
167 control_t *ins_ctrl(int type, int special_style, control_t *ctrl, control_t *prev);
168 dialog_t *dialog_version(version_t *v, dialog_t *dlg);
169 dialog_t *dialog_characteristics(characts_t *c, dialog_t *dlg);
170 dialog_t *dialog_language(language_t *l, dialog_t *dlg);
171 dialog_t *dialog_menu(name_id_t *m, dialog_t *dlg);
172 dialog_t *dialog_class(name_id_t *n, dialog_t *dlg);
173 dialog_t *dialog_font(font_id_t *f, dialog_t *dlg);
174 dialog_t *dialog_caption(string_t *s, dialog_t *dlg);
175 dialog_t *dialog_exstyle(style_t * st, dialog_t *dlg);
176 dialog_t *dialog_style(style_t * st, dialog_t *dlg);
177 resource_t *build_stt_resources(stringtable_t *stthead);
178 stringtable_t *find_stringtable(lvc_t *lvc);
179 toolbar_item_t *ins_tlbr_button(toolbar_item_t *prev, toolbar_item_t *idrec);
180 toolbar_item_t *get_tlbr_buttons_head(toolbar_item_t *p, int *nitems);
183 %union{
184 string_t *str;
185 int num;
186 int *iptr;
187 resource_t *res;
188 accelerator_t *acc;
189 bitmap_t *bmp;
190 cursor_t *cur;
191 cursor_group_t *curg;
192 dialog_t *dlg;
193 dialogex_t *dlgex;
194 font_t *fnt;
195 icon_t *ico;
196 icon_group_t *icog;
197 menu_t *men;
198 menuex_t *menex;
199 rcdata_t *rdt;
200 stringtable_t *stt;
201 stt_entry_t *stte;
202 user_t *usr;
203 messagetable_t *msg;
204 versioninfo_t *veri;
205 control_t *ctl;
206 name_id_t *nid;
207 font_id_t *fntid;
208 language_t *lan;
209 version_t *ver;
210 characts_t *chars;
211 event_t *event;
212 menu_item_t *menitm;
213 menuex_item_t *menexitm;
214 itemex_opt_t *exopt;
215 raw_data_t *raw;
216 lvc_t *lvc;
217 ver_value_t *val;
218 ver_block_t *blk;
219 ver_words_t *verw;
220 toolbar_t *tlbar;
221 toolbar_item_t *tlbarItems;
222 dlginit_t *dginit;
223 style_pair_t *styles;
224 style_t *style;
227 %token tIF tIFDEF tIFNDEF tELSE tELIF tENDIF tDEFINED tNL
228 %token tTYPEDEF tEXTERN
229 %token <num> NUMBER LNUMBER
230 %token <str> tSTRING IDENT FILENAME
231 %token <raw> RAWDATA
232 %token ACCELERATORS tBITMAP CURSOR DIALOG DIALOGEX MENU MENUEX MESSAGETABLE
233 %token RCDATA VERSIONINFO STRINGTABLE FONT ICON
234 %token AUTO3STATE AUTOCHECKBOX AUTORADIOBUTTON CHECKBOX DEFPUSHBUTTON
235 %token PUSHBUTTON RADIOBUTTON STATE3 /* PUSHBOX */
236 %token GROUPBOX COMBOBOX LISTBOX SCROLLBAR
237 %token CONTROL EDITTEXT
238 %token RTEXT CTEXT LTEXT
239 %token BLOCK VALUE
240 %token SHIFT ALT ASCII VIRTKEY GRAYED CHECKED INACTIVE NOINVERT
241 %token tPURE IMPURE DISCARDABLE LOADONCALL PRELOAD tFIXED MOVEABLE
242 %token CLASS CAPTION CHARACTERISTICS EXSTYLE STYLE VERSION LANGUAGE
243 %token FILEVERSION PRODUCTVERSION FILEFLAGSMASK FILEOS FILETYPE FILEFLAGS FILESUBTYPE
244 %token MENUBARBREAK MENUBREAK MENUITEM POPUP SEPARATOR
245 %token HELP
246 %token tSTRING IDENT RAWDATA
247 %token TOOLBAR BUTTON
248 %token tBEGIN tEND
249 %token DLGINIT
250 %left LOGOR
251 %left LOGAND
252 %left '|'
253 %left '^'
254 %left '&'
255 %left EQ NE
256 %left '<' LTE '>' GTE
257 %left '+' '-'
258 %left '*' '/'
259 %right '~' '!' NOT
261 %type <res> resource_file resource resources resource_definition
262 %type <stt> stringtable strings
263 %type <fnt> font
264 %type <icog> icon
265 %type <acc> accelerators
266 %type <event> events
267 %type <bmp> bitmap
268 %type <curg> cursor
269 %type <dlg> dialog dlg_attributes
270 %type <ctl> ctrls gen_ctrl lab_ctrl ctrl_desc iconinfo
271 %type <iptr> helpid
272 %type <dlgex> dialogex dlgex_attribs
273 %type <ctl> exctrls gen_exctrl lab_exctrl exctrl_desc
274 %type <rdt> rcdata
275 %type <raw> raw_data raw_elements opt_data
276 %type <veri> versioninfo fix_version
277 %type <verw> ver_words
278 %type <blk> ver_blocks ver_block
279 %type <val> ver_values ver_value
280 %type <men> menu
281 %type <menitm> item_definitions menu_body
282 %type <menex> menuex
283 %type <menexitm> itemex_definitions menuex_body
284 %type <exopt> itemex_p_options itemex_options
285 %type <msg> messagetable
286 %type <usr> userres
287 %type <num> item_options
288 %type <nid> nameid nameid_s ctlclass usertype
289 %type <num> acc_opt
290 %type <iptr> loadmemopts lamo lama
291 %type <fntid> opt_font opt_exfont opt_expr
292 %type <lvc> opt_lvc
293 %type <lan> opt_language
294 %type <chars> opt_characts
295 %type <ver> opt_version
296 %type <num> expr xpr
297 %type <iptr> e_expr
298 %type <iptr> pp_expr pp_constant
299 %type <tlbar> toolbar
300 %type <tlbarItems> toolbar_items
301 %type <dginit> dlginit
302 %type <styles> optional_style_pair
303 %type <num> any_num
304 %type <style> optional_style
305 %type <style> style
309 resource_file
310 : resources {
311 resource_t *rsc;
312 /* First add stringtables to the resource-list */
313 rsc = build_stt_resources(sttres);
314 /* 'build_stt_resources' returns a head and $1 is a tail */
315 if($1)
317 $1->next = rsc;
318 if(rsc)
319 rsc->prev = $1;
321 else
322 $1 = rsc;
323 /* Final statement before were done */
324 resource_top = get_resource_head($1);
328 /* Resources are put into a linked list */
329 resources
330 : /* Empty */ { $$ = NULL; want_rscname = 1; }
331 | resources resource {
332 if($2)
334 resource_t *tail = $2;
335 resource_t *head = $2;
336 while(tail->next)
337 tail = tail->next;
338 while(head->prev)
339 head = head->prev;
340 head->prev = $1;
341 if($1)
342 $1->next = head;
343 $$ = tail;
345 else if($1)
347 resource_t *tail = $1;
348 while(tail->next)
349 tail = tail->next;
350 $$ = tail;
352 else
353 $$ = NULL;
354 want_rscname = 1;
356 | resources preprocessor { $$ = $1; want_rscname = 1; }
357 | resources cjunk { $$ = $1; want_rscname = 1; }
360 /* The buildin preprocessor */
361 preprocessor
362 : tIF pp_expr tNL { pop_start(); push_if($2 ? *($2) : 0, 0, 0); if($2) free($2);}
363 | tIFDEF IDENT tNL { pop_start(); push_if(pp_lookup($2->str.cstr) != NULL, 0, 0); }
364 | tIFNDEF IDENT tNL { pop_start(); push_if(pp_lookup($2->str.cstr) == NULL, 0, 0); }
365 | tELIF pp_expr tNL { pop_start(); push_if($2 ? *($2) : 0, pop_if(), 0); if($2) free($2); }
366 | tELSE tNL { pop_start(); push_if(1, pop_if(), 0); }
367 | tENDIF tNL { pop_if(); }
370 pp_expr : pp_constant { $$ = $1; }
371 | pp_expr LOGOR pp_expr { $$ = new_int($1 && $3 ? (*$1 || *$3) : 0); if($1) free($1); if($3) free($3); }
372 | pp_expr LOGAND pp_expr { $$ = new_int($1 && $3 ? (*$1 && *$3) : 0); if($1) free($1); if($3) free($3); }
373 | pp_expr '+' pp_expr { $$ = new_int($1 && $3 ? (*$1 + *$3) : 0); if($1) free($1); if($3) free($3); }
374 | pp_expr '-' pp_expr { $$ = new_int($1 && $3 ? (*$1 - *$3) : 0); if($1) free($1); if($3) free($3); }
375 | pp_expr '^' pp_expr { $$ = new_int($1 && $3 ? (*$1 ^ *$3) : 0); if($1) free($1); if($3) free($3); }
376 | pp_expr EQ pp_expr { $$ = new_int($1 && $3 ? (*$1 == *$3) : 0); if($1) free($1); if($3) free($3); }
377 | pp_expr NE pp_expr { $$ = new_int($1 && $3 ? (*$1 != *$3) : 0); if($1) free($1); if($3) free($3); }
378 | pp_expr '<' pp_expr { $$ = new_int($1 && $3 ? (*$1 < *$3) : 0); if($1) free($1); if($3) free($3); }
379 | pp_expr '>' pp_expr { $$ = new_int($1 && $3 ? (*$1 > *$3) : 0); if($1) free($1); if($3) free($3); }
380 | pp_expr LTE pp_expr { $$ = new_int($1 && $3 ? (*$1 <= *$3) : 0); if($1) free($1); if($3) free($3); }
381 | pp_expr GTE pp_expr { $$ = new_int($1 && $3 ? (*$1 >= *$3) : 0); if($1) free($1); if($3) free($3); }
382 | '~' pp_expr { $$ = $2; if($2) *$2 = ~(*$2); }
383 | '+' pp_expr { $$ = $2; }
384 | '-' pp_expr { $$ = $2; if($2) *$2 = -(*$2); }
385 | '!' pp_expr { $$ = $2; if($2) *$2 = !(*$2); }
386 | '(' pp_expr ')' { $$ = $2; }
389 pp_constant
390 : any_num { $$ = new_int($1); }
391 | IDENT { $$ = NULL; }
392 | tDEFINED IDENT { $$ = new_int(pp_lookup($2->str.cstr) != NULL); }
393 | tDEFINED '(' IDENT ')' { $$ = new_int(pp_lookup($3->str.cstr) != NULL); }
396 /* C ignore stuff */
397 cjunk : tTYPEDEF { strip_til_semicolon(); }
398 | tEXTERN { strip_til_semicolon(); }
399 | IDENT IDENT { strip_til_semicolon(); }
400 | IDENT '(' { strip_til_parenthesis(); }
401 | IDENT '*' { strip_til_semicolon(); }
404 /* Parse top level resource definitions etc. */
405 resource
406 : nameid resource_definition {
407 $$ = $2;
408 if($$)
410 $$->name = $1;
411 if($1->type == name_ord)
413 chat("Got %s (%d)",get_typename($2),$1->name.i_name);
415 else if($1->type == name_str)
417 chat("Got %s (%s)",get_typename($2),$1->name.s_name->str.cstr);
421 | stringtable {
422 /* Don't do anything, stringtables are converted to
423 * resource_t structures when we are finished parsing and
424 * the final rule of the parser is reduced (see above)
426 $$ = NULL;
427 chat("Got STRINGTABLE");
429 | opt_language {
430 if(!win32)
431 yywarning("LANGUAGE not supported in 16-bit mode");
432 if(currentlanguage)
433 free(currentlanguage);
434 currentlanguage = $1;
435 $$ = NULL;
440 * Get a valid name/id
442 nameid : expr {
443 if($1 > 65535 || $1 < -32768)
444 yyerror("Resource's ID out of range (%d)", $1);
445 $$ = new_name_id();
446 $$->type = name_ord;
447 $$->name.i_name = $1;
448 want_rscname = 0;
450 | IDENT {
451 $$ = new_name_id();
452 $$->type = name_str;
453 $$->name.s_name = $1;
454 want_rscname = 0;
459 * Extra string recognition for CLASS statement in dialogs
461 nameid_s: nameid { $$ = $1; }
462 | tSTRING {
463 $$ = new_name_id();
464 $$->type = name_str;
465 $$->name.s_name = $1;
466 want_rscname = 0;
470 /* get the value for a single resource*/
471 resource_definition
472 : accelerators { $$ = new_resource(res_acc, $1, $1->memopt, $1->lvc.language); }
473 | bitmap { $$ = new_resource(res_bmp, $1, $1->memopt, dup_language(currentlanguage)); }
474 | cursor {
475 resource_t *rsc;
476 cursor_t *cur;
477 $$ = rsc = new_resource(res_curg, $1, $1->memopt, dup_language(currentlanguage));
478 for(cur = $1->cursorlist; cur; cur = cur->next)
480 rsc->prev = new_resource(res_cur, cur, $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 = cur->id;
488 | dialog { $$ = new_resource(res_dlg, $1, $1->memopt, $1->lvc.language); }
489 | dialogex {
490 if(win32)
491 $$ = new_resource(res_dlgex, $1, $1->memopt, $1->lvc.language);
492 else
493 $$ = NULL;
495 | dlginit { $$ = new_resource(res_dlginit, $1, $1->memopt, $1->lvc.language); }
496 | font { $$ = new_resource(res_fnt, $1, $1->memopt, dup_language(currentlanguage)); }
497 | icon {
498 resource_t *rsc;
499 icon_t *ico;
500 $$ = rsc = new_resource(res_icog, $1, $1->memopt, dup_language(currentlanguage));
501 for(ico = $1->iconlist; ico; ico = ico->next)
503 rsc->prev = new_resource(res_ico, ico, $1->memopt, dup_language(currentlanguage));
504 rsc->prev->next = rsc;
505 rsc = rsc->prev;
506 rsc->name = new_name_id();
507 rsc->name->type = name_ord;
508 rsc->name->name.i_name = ico->id;
511 | menu { $$ = new_resource(res_men, $1, $1->memopt, $1->lvc.language); }
512 | menuex {
513 if(win32)
514 $$ = new_resource(res_menex, $1, $1->memopt, $1->lvc.language);
515 else
516 $$ = NULL;
518 | messagetable { $$ = new_resource(res_msg, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, dup_language(currentlanguage)); }
519 | rcdata { $$ = new_resource(res_rdt, $1, $1->memopt, $1->lvc.language); }
520 | toolbar { $$ = new_resource(res_toolbar, $1, $1->memopt, $1->lvc.language); }
521 | userres { $$ = new_resource(res_usr, $1, $1->memopt, dup_language(currentlanguage)); }
522 | versioninfo { $$ = new_resource(res_ver, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, dup_language(currentlanguage)); }
525 /* ------------------------------ Bitmap ------------------------------ */
526 bitmap : tBITMAP loadmemopts FILENAME { $$ = new_bitmap(load_file($3), $2); }
527 | tBITMAP loadmemopts raw_data { $$ = new_bitmap($3, $2); }
530 /* ------------------------------ Cursor ------------------------------ */
531 cursor : CURSOR loadmemopts FILENAME { $$ = new_cursor_group(load_file($3), $2); }
532 | CURSOR loadmemopts raw_data { $$ = new_cursor_group($3, $2); }
535 /* ------------------------------ Font ------------------------------ */
536 /* FIXME: Should we allow raw_data here? */
537 font : FONT loadmemopts FILENAME { $$ = new_font(load_file($3), $2); }
540 /* ------------------------------ Icon ------------------------------ */
541 icon : ICON loadmemopts FILENAME { $$ = new_icon_group(load_file($3), $2); }
542 | ICON loadmemopts raw_data { $$ = new_icon_group($3, $2); }
545 /* ------------------------------ MessageTable ------------------------------ */
546 /* It might be interesting to implement the MS Message compiler here as well
547 * to get everything in one source. Might be a future project.
549 messagetable
550 : MESSAGETABLE FILENAME {
551 if(!win32)
552 yywarning("MESSAGETABLE not supported in 16-bit mode");
553 $$ = new_messagetable(load_file($2));
557 /* ------------------------------ RCData ------------------------------ */
558 rcdata : RCDATA loadmemopts opt_lvc raw_data {
559 $$ = new_rcdata($4, $2);
560 if($3)
562 $$->lvc = *($3);
563 free($3);
565 if(!$$->lvc.language)
566 $$->lvc.language = dup_language(currentlanguage);
570 /* ------------------------------ DLGINIT ------------------------------ */
571 dlginit : DLGINIT loadmemopts opt_lvc raw_data {
572 $$ = new_dlginit($4, $2);
573 if($3)
575 $$->lvc = *($3);
576 free($3);
578 if(!$$->lvc.language)
579 $$->lvc.language = dup_language(currentlanguage);
583 /* ------------------------------ UserType ------------------------------ */
584 userres : usertype loadmemopts FILENAME { $$ = new_user($1, load_file($3), $2); }
585 | usertype loadmemopts raw_data { $$ = new_user($1, $3, $2); }
588 /* NOTE: This here is an exception where I do not allow an expression.
589 * Reason for this is that it is not possible to set the 'yywf' condition
590 * for flex if loadmemopts is empty. Reading an expression requires a
591 * lookahead to determine its end. In this case here, that would mean that
592 * the filename has been read as IDENT or tSTRING, which is incorrect.
593 * Note also that IDENT cannot be used as a file-name because it is lacking
594 * the '.'.
597 /* I also allow string identifiers as classtypes. Not MS implemented, but
598 * seems to be reasonable to implement.
600 /* Allowing anything else than NUMBER makes it very hard to get rid of
601 * prototypes. So, I remove IDENT to be able to get prototypes out of the
602 * world.
604 usertype: NUMBER {
605 $$ = new_name_id();
606 $$->type = name_ord;
607 $$->name.i_name = $1;
608 set_yywf();
610 /* | IDENT {
611 $$ = new_name_id();
612 $$->type = name_str;
613 $$->name.s_name = $1;
614 set_yywf();
616 */ | tSTRING {
617 $$ = new_name_id();
618 $$->type = name_str;
619 $$->name.s_name = $1;
620 set_yywf();
624 /* ------------------------------ Accelerator ------------------------------ */
625 accelerators
626 : ACCELERATORS loadmemopts opt_lvc tBEGIN events tEND {
627 $$ = new_accelerator();
628 if($2)
630 $$->memopt = *($2);
631 free($2);
633 else
635 $$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
637 if(!$5)
638 yyerror("Accelerator table must have at least one entry");
639 $$->events = get_event_head($5);
640 if($3)
642 $$->lvc = *($3);
643 free($3);
645 if(!$$->lvc.language)
646 $$->lvc.language = dup_language(currentlanguage);
650 events : /* Empty */ { $$=NULL; }
651 | events tSTRING ',' expr acc_opt { $$=add_string_event($2, $4, $5, $1); }
652 | events expr ',' expr acc_opt { $$=add_event($2, $4, $5, $1); }
655 acc_opt : /* Empty */ { $$=0; }
656 | acc_opt ',' NOINVERT { $$=$1 | WRC_AF_NOINVERT; }
657 | acc_opt ',' SHIFT { $$=$1 | WRC_AF_SHIFT; }
658 | acc_opt ',' CONTROL { $$=$1 | WRC_AF_CONTROL; }
659 | acc_opt ',' ALT { $$=$1 | WRC_AF_ALT; }
660 | acc_opt ',' ASCII { $$=$1 | WRC_AF_ASCII; }
661 | acc_opt ',' VIRTKEY { $$=$1 | WRC_AF_VIRTKEY; }
664 /* ------------------------------ Dialog ------------------------------ */
665 /* FIXME: Support EXSTYLE in the dialog line itself */
666 dialog : DIALOG loadmemopts expr ',' expr ',' expr ',' expr dlg_attributes
667 tBEGIN ctrls tEND {
668 if($2)
670 $10->memopt = *($2);
671 free($2);
673 else
674 $10->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
675 $10->x = $3;
676 $10->y = $5;
677 $10->width = $7;
678 $10->height = $9;
679 $10->controls = get_control_head($12);
680 $$ = $10;
681 if(!$$->gotstyle)
683 $$->style->or_mask = WS_POPUP;
684 $$->gotstyle = TRUE;
686 if($$->title)
687 $$->style->or_mask |= WS_CAPTION;
688 if($$->font)
689 $$->style->or_mask |= DS_SETFONT;
691 $$->style->or_mask &= ~($$->style->and_mask);
692 $$->style->and_mask = 0;
694 indialog = FALSE;
695 if(!$$->lvc.language)
696 $$->lvc.language = dup_language(currentlanguage);
700 dlg_attributes
701 : /* Empty */ { $$=new_dialog(); }
702 | dlg_attributes STYLE style { $$=dialog_style($3,$1); }
703 | dlg_attributes EXSTYLE style { $$=dialog_exstyle($3,$1); }
704 | dlg_attributes CAPTION tSTRING { $$=dialog_caption($3,$1); }
705 | dlg_attributes opt_font { $$=dialog_font($2,$1); }
706 | dlg_attributes CLASS nameid_s { $$=dialog_class($3,$1); }
707 | dlg_attributes MENU nameid { $$=dialog_menu($3,$1); }
708 | dlg_attributes opt_language { $$=dialog_language($2,$1); }
709 | dlg_attributes opt_characts { $$=dialog_characteristics($2,$1); }
710 | dlg_attributes opt_version { $$=dialog_version($2,$1); }
713 ctrls : /* Empty */ { $$ = NULL; }
714 | ctrls CONTROL gen_ctrl { $$=ins_ctrl(-1, 0, $3, $1); }
715 | ctrls EDITTEXT ctrl_desc { $$=ins_ctrl(CT_EDIT, 0, $3, $1); }
716 | ctrls LISTBOX ctrl_desc { $$=ins_ctrl(CT_LISTBOX, 0, $3, $1); }
717 | ctrls COMBOBOX ctrl_desc { $$=ins_ctrl(CT_COMBOBOX, 0, $3, $1); }
718 | ctrls SCROLLBAR ctrl_desc { $$=ins_ctrl(CT_SCROLLBAR, 0, $3, $1); }
719 | ctrls CHECKBOX lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_CHECKBOX, $3, $1); }
720 | ctrls DEFPUSHBUTTON lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_DEFPUSHBUTTON, $3, $1); }
721 | ctrls GROUPBOX lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_GROUPBOX, $3, $1);}
722 | ctrls PUSHBUTTON lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBUTTON, $3, $1); }
723 /* | ctrls PUSHBOX lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
724 | ctrls RADIOBUTTON lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_RADIOBUTTON, $3, $1); }
725 | ctrls AUTO3STATE lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_AUTO3STATE, $3, $1); }
726 | ctrls STATE3 lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_3STATE, $3, $1); }
727 | ctrls AUTOCHECKBOX lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_AUTOCHECKBOX, $3, $1); }
728 | ctrls AUTORADIOBUTTON lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_AUTORADIOBUTTON, $3, $1); }
729 | ctrls LTEXT lab_ctrl { $$=ins_ctrl(CT_STATIC, SS_LEFT, $3, $1); }
730 | ctrls CTEXT lab_ctrl { $$=ins_ctrl(CT_STATIC, SS_CENTER, $3, $1); }
731 | ctrls RTEXT lab_ctrl { $$=ins_ctrl(CT_STATIC, SS_RIGHT, $3, $1); }
732 /* special treatment for icons, as the extent is optional */
733 | ctrls ICON nameid_s ',' expr ',' expr ',' expr iconinfo {
734 $10->title = $3;
735 $10->id = $5;
736 $10->x = $7;
737 $10->y = $9;
738 $$ = ins_ctrl(CT_STATIC, SS_ICON, $10, $1);
742 lab_ctrl
743 : tSTRING ',' expr ',' expr ',' expr ',' expr ',' expr optional_style {
744 $$=new_control();
745 $$->title = new_name_id();
746 $$->title->type = name_str;
747 $$->title->name.s_name = $1;
748 $$->id = $3;
749 $$->x = $5;
750 $$->y = $7;
751 $$->width = $9;
752 $$->height = $11;
753 if($12)
755 $$->style = $12;
756 $$->gotstyle = TRUE;
761 ctrl_desc
762 : expr ',' expr ',' expr ',' expr ',' expr optional_style {
763 $$ = new_control();
764 $$->id = $1;
765 $$->x = $3;
766 $$->y = $5;
767 $$->width = $7;
768 $$->height = $9;
769 if($10)
771 $$->style = $10;
772 $$->gotstyle = TRUE;
777 iconinfo: /* Empty */
778 { $$ = new_control(); }
780 | ',' expr ',' expr {
781 $$ = new_control();
782 $$->width = $2;
783 $$->height = $4;
785 | ',' expr ',' expr ',' style {
786 $$ = new_control();
787 $$->width = $2;
788 $$->height = $4;
789 $$->style = $6;
790 $$->gotstyle = TRUE;
792 | ',' expr ',' expr ',' style ',' style {
793 $$ = new_control();
794 $$->width = $2;
795 $$->height = $4;
796 $$->style = $6;
797 $$->gotstyle = TRUE;
798 $$->exstyle = $8;
799 $$->gotexstyle = TRUE;
803 gen_ctrl: nameid_s ',' expr ',' ctlclass ',' style ',' expr ',' expr ',' expr ',' expr ',' style {
804 $$=new_control();
805 $$->title = $1;
806 $$->id = $3;
807 $$->ctlclass = convert_ctlclass($5);
808 $$->style = $7;
809 $$->gotstyle = TRUE;
810 $$->x = $9;
811 $$->y = $11;
812 $$->width = $13;
813 $$->height = $15;
814 $$->exstyle = $17;
815 $$->gotexstyle = TRUE;
817 | nameid_s ',' expr ',' ctlclass ',' style ',' expr ',' expr ',' expr ',' expr {
818 $$=new_control();
819 $$->title = $1;
820 $$->id = $3;
821 $$->ctlclass = convert_ctlclass($5);
822 $$->style = $7;
823 $$->gotstyle = TRUE;
824 $$->x = $9;
825 $$->y = $11;
826 $$->width = $13;
827 $$->height = $15;
831 opt_font
832 : FONT expr ',' tSTRING { $$ = new_font_id($2, $4, 0, 0); }
835 /* ------------------------------ style flags ------------------------------ */
836 optional_style /* Abbused once to get optional ExStyle */
837 : /* Empty */ { $$ = NULL; }
838 | ',' style { $$ = $2; }
841 optional_style_pair
842 : /* Empty */ { $$ = NULL; }
843 | ',' style { $$ = new_style_pair($2, 0); }
844 | ',' style ',' style { $$ = new_style_pair($2, $4); }
847 style
848 : style '|' style { $$ = new_style($1->or_mask | $3->or_mask, $1->and_mask | $3->and_mask); free($1); free($3);}
849 | '(' style ')' { $$ = $2; }
850 | any_num { $$ = new_style($1, 0); }
851 | NOT any_num { $$ = new_style(0, $2); }
854 ctlclass
855 : expr {
856 $$ = new_name_id();
857 $$->type = name_ord;
858 $$->name.i_name = $1;
860 | tSTRING {
861 $$ = new_name_id();
862 $$->type = name_str;
863 $$->name.s_name = $1;
867 /* ------------------------------ DialogEx ------------------------------ */
868 dialogex: DIALOGEX loadmemopts expr ',' expr ',' expr ',' expr helpid dlgex_attribs
869 tBEGIN exctrls tEND {
870 if(!win32)
871 yywarning("DIALOGEX not supported in 16-bit mode");
872 if($2)
874 $11->memopt = *($2);
875 free($2);
877 else
878 $11->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
879 $11->x = $3;
880 $11->y = $5;
881 $11->width = $7;
882 $11->height = $9;
883 if($10)
885 $11->helpid = *($10);
886 $11->gothelpid = TRUE;
887 free($10);
889 $11->controls = get_control_head($13);
890 $$ = $11;
892 assert($$->style != NULL);
893 if(!$$->gotstyle)
895 $$->style->or_mask = WS_POPUP;
896 $$->gotstyle = TRUE;
898 if($$->title)
899 $$->style->or_mask |= WS_CAPTION;
900 if($$->font)
901 $$->style->or_mask |= DS_SETFONT;
903 $$->style->or_mask &= ~($$->style->and_mask);
904 $$->style->and_mask = 0;
906 indialog = FALSE;
907 if(!$$->lvc.language)
908 $$->lvc.language = dup_language(currentlanguage);
912 dlgex_attribs
913 : /* Empty */ { $$=new_dialogex(); }
914 | dlgex_attribs STYLE style { $$=dialogex_style($3,$1); }
915 | dlgex_attribs EXSTYLE style { $$=dialogex_exstyle($3,$1); }
916 | dlgex_attribs CAPTION tSTRING { $$=dialogex_caption($3,$1); }
917 | dlgex_attribs opt_font { $$=dialogex_font($2,$1); }
918 | dlgex_attribs opt_exfont { $$=dialogex_font($2,$1); }
919 | dlgex_attribs CLASS nameid_s { $$=dialogex_class($3,$1); }
920 | dlgex_attribs MENU nameid { $$=dialogex_menu($3,$1); }
921 | dlgex_attribs opt_language { $$=dialogex_language($2,$1); }
922 | dlgex_attribs opt_characts { $$=dialogex_characteristics($2,$1); }
923 | dlgex_attribs opt_version { $$=dialogex_version($2,$1); }
926 exctrls : /* Empty */ { $$ = NULL; }
927 | exctrls CONTROL gen_exctrl { $$=ins_ctrl(-1, 0, $3, $1); }
928 | exctrls EDITTEXT exctrl_desc { $$=ins_ctrl(CT_EDIT, 0, $3, $1); }
929 | exctrls LISTBOX exctrl_desc { $$=ins_ctrl(CT_LISTBOX, 0, $3, $1); }
930 | exctrls COMBOBOX exctrl_desc { $$=ins_ctrl(CT_COMBOBOX, 0, $3, $1); }
931 | exctrls SCROLLBAR exctrl_desc { $$=ins_ctrl(CT_SCROLLBAR, 0, $3, $1); }
932 | exctrls CHECKBOX lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_CHECKBOX, $3, $1); }
933 | exctrls DEFPUSHBUTTON lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_DEFPUSHBUTTON, $3, $1); }
934 | exctrls GROUPBOX lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_GROUPBOX, $3, $1);}
935 | exctrls PUSHBUTTON lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBUTTON, $3, $1); }
936 /* | exctrls PUSHBOX lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
937 | exctrls RADIOBUTTON lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_RADIOBUTTON, $3, $1); }
938 | exctrls AUTO3STATE lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_AUTO3STATE, $3, $1); }
939 | exctrls STATE3 lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_3STATE, $3, $1); }
940 | exctrls AUTOCHECKBOX lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_AUTOCHECKBOX, $3, $1); }
941 | exctrls AUTORADIOBUTTON lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_AUTORADIOBUTTON, $3, $1); }
942 | exctrls LTEXT lab_exctrl { $$=ins_ctrl(CT_STATIC, SS_LEFT, $3, $1); }
943 | exctrls CTEXT lab_exctrl { $$=ins_ctrl(CT_STATIC, SS_CENTER, $3, $1); }
944 | exctrls RTEXT lab_exctrl { $$=ins_ctrl(CT_STATIC, SS_RIGHT, $3, $1); }
945 /* special treatment for icons, as the extent is optional */
946 | exctrls ICON nameid_s ',' expr ',' expr ',' expr iconinfo {
947 $10->title = $3;
948 $10->id = $5;
949 $10->x = $7;
950 $10->y = $9;
951 $$ = ins_ctrl(CT_STATIC, SS_ICON, $10, $1);
955 gen_exctrl
956 : nameid_s ',' expr ',' ctlclass ',' style ',' expr ',' expr ',' expr ','
957 expr ',' style helpid opt_data {
958 $$=new_control();
959 $$->title = $1;
960 $$->id = $3;
961 $$->ctlclass = convert_ctlclass($5);
962 $$->style = $7;
963 $$->gotstyle = TRUE;
964 $$->x = $9;
965 $$->y = $11;
966 $$->width = $13;
967 $$->height = $15;
968 if($17)
970 $$->exstyle = $17;
971 $$->gotexstyle = TRUE;
973 if($18)
975 $$->helpid = *($18);
976 $$->gothelpid = TRUE;
977 free($18);
979 $$->extra = $19;
981 | nameid_s ',' expr ',' ctlclass ',' style ',' expr ',' expr ',' expr ',' expr opt_data {
982 $$=new_control();
983 $$->title = $1;
984 $$->id = $3;
985 $$->style = $7;
986 $$->gotstyle = TRUE;
987 $$->ctlclass = convert_ctlclass($5);
988 $$->x = $9;
989 $$->y = $11;
990 $$->width = $13;
991 $$->height = $15;
992 $$->extra = $16;
996 lab_exctrl
997 : tSTRING ',' expr ',' expr ',' expr ',' expr ',' expr optional_style_pair opt_data {
998 $$=new_control();
999 $$->title = new_name_id();
1000 $$->title->type = name_str;
1001 $$->title->name.s_name = $1;
1002 $$->id = $3;
1003 $$->x = $5;
1004 $$->y = $7;
1005 $$->width = $9;
1006 $$->height = $11;
1007 if($12)
1009 $$->style = $12->style;
1010 $$->gotstyle = TRUE;
1012 if ($12->exstyle)
1014 $$->exstyle = $12->exstyle;
1015 $$->gotexstyle = TRUE;
1017 free($12);
1020 $$->extra = $13;
1024 exctrl_desc
1025 : expr ',' expr ',' expr ',' expr ',' expr optional_style_pair opt_data {
1026 $$ = new_control();
1027 $$->id = $1;
1028 $$->x = $3;
1029 $$->y = $5;
1030 $$->width = $7;
1031 $$->height = $9;
1032 if($10)
1034 $$->style = $10->style;
1035 $$->gotstyle = TRUE;
1037 if ($10->exstyle)
1039 $$->exstyle = $10->exstyle;
1040 $$->gotexstyle = TRUE;
1042 free($10);
1044 $$->extra = $11;
1048 opt_data: /* Empty */ { $$ = NULL; }
1049 | raw_data { $$ = $1; }
1052 helpid : /* Empty */ { $$ = NULL; }
1053 | ',' expr { $$ = new_int($2); }
1056 opt_exfont
1057 : FONT expr ',' tSTRING ',' expr ',' expr opt_expr { $$ = new_font_id($2, $4, $6, $8); }
1061 * FIXME: This odd expression is here to nullify an extra token found
1062 * in some appstudio produced resources which appear to do nothing.
1064 opt_expr: /* Empty */ { $$ = NULL; }
1065 | ',' expr { $$ = NULL; }
1068 /* ------------------------------ Menu ------------------------------ */
1069 menu : MENU loadmemopts opt_lvc menu_body {
1070 if(!$4)
1071 yyerror("Menu must contain items");
1072 $$ = new_menu();
1073 if($2)
1075 $$->memopt = *($2);
1076 free($2);
1078 else
1079 $$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
1080 $$->items = get_item_head($4);
1081 if($3)
1083 $$->lvc = *($3);
1084 free($3);
1086 if(!$$->lvc.language)
1087 $$->lvc.language = dup_language(currentlanguage);
1091 menu_body
1092 : tBEGIN item_definitions tEND { $$ = $2; }
1095 item_definitions
1096 : /* Empty */ {$$ = NULL;}
1097 | item_definitions MENUITEM tSTRING ',' expr item_options {
1098 $$=new_menu_item();
1099 $$->prev = $1;
1100 if($1)
1101 $1->next = $$;
1102 $$->id = $5;
1103 $$->state = $6;
1104 $$->name = $3;
1106 | item_definitions MENUITEM SEPARATOR {
1107 $$=new_menu_item();
1108 $$->prev = $1;
1109 if($1)
1110 $1->next = $$;
1112 | item_definitions POPUP tSTRING item_options menu_body {
1113 $$ = new_menu_item();
1114 $$->prev = $1;
1115 if($1)
1116 $1->next = $$;
1117 $$->popup = get_item_head($5);
1118 $$->name = $3;
1122 /* NOTE: item_options is right recursive because it would introduce
1123 * a shift/reduce conflict on ',' in itemex_options due to the
1124 * empty rule here. The parser is now forced to look beyond the ','
1125 * before reducing (force shift).
1126 * Right recursion here is not a problem because we cannot expect
1127 * more than 7 parserstack places to be occupied while parsing this
1128 * (who would want to specify a MF_x flag twice?).
1130 item_options
1131 : /* Empty */ { $$ = 0; }
1132 | ',' CHECKED item_options { $$ = $3 | MF_CHECKED; }
1133 | ',' GRAYED item_options { $$ = $3 | MF_GRAYED; }
1134 | ',' HELP item_options { $$ = $3 | MF_HELP; }
1135 | ',' INACTIVE item_options { $$ = $3 | MF_DISABLED; }
1136 | ',' MENUBARBREAK item_options { $$ = $3 | MF_MENUBARBREAK; }
1137 | ',' MENUBREAK item_options { $$ = $3 | MF_MENUBREAK; }
1140 /* ------------------------------ MenuEx ------------------------------ */
1141 menuex : MENUEX loadmemopts opt_lvc menuex_body {
1142 if(!win32)
1143 yywarning("MENUEX not supported in 16-bit mode");
1144 if(!$4)
1145 yyerror("MenuEx must contain items");
1146 $$ = new_menuex();
1147 if($2)
1149 $$->memopt = *($2);
1150 free($2);
1152 else
1153 $$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
1154 $$->items = get_itemex_head($4);
1155 if($3)
1157 $$->lvc = *($3);
1158 free($3);
1160 if(!$$->lvc.language)
1161 $$->lvc.language = dup_language(currentlanguage);
1165 menuex_body
1166 : tBEGIN itemex_definitions tEND { $$ = $2; }
1169 itemex_definitions
1170 : /* Empty */ {$$ = NULL; }
1171 | itemex_definitions MENUITEM tSTRING itemex_options {
1172 $$ = new_menuex_item();
1173 $$->prev = $1;
1174 if($1)
1175 $1->next = $$;
1176 $$->name = $3;
1177 $$->id = $4->id;
1178 $$->type = $4->type;
1179 $$->state = $4->state;
1180 $$->helpid = $4->helpid;
1181 $$->gotid = $4->gotid;
1182 $$->gottype = $4->gottype;
1183 $$->gotstate = $4->gotstate;
1184 $$->gothelpid = $4->gothelpid;
1185 free($4);
1187 | itemex_definitions MENUITEM SEPARATOR {
1188 $$ = new_menuex_item();
1189 $$->prev = $1;
1190 if($1)
1191 $1->next = $$;
1193 | itemex_definitions POPUP tSTRING itemex_p_options menuex_body {
1194 $$ = new_menuex_item();
1195 $$->prev = $1;
1196 if($1)
1197 $1->next = $$;
1198 $$->popup = get_itemex_head($5);
1199 $$->name = $3;
1200 $$->id = $4->id;
1201 $$->type = $4->type;
1202 $$->state = $4->state;
1203 $$->helpid = $4->helpid;
1204 $$->gotid = $4->gotid;
1205 $$->gottype = $4->gottype;
1206 $$->gotstate = $4->gotstate;
1207 $$->gothelpid = $4->gothelpid;
1208 free($4);
1212 itemex_options
1213 : /* Empty */ { $$ = new_itemex_opt(0, 0, 0, 0); }
1214 | ',' expr {
1215 $$ = new_itemex_opt($2, 0, 0, 0);
1216 $$->gotid = TRUE;
1218 | ',' e_expr ',' e_expr item_options {
1219 $$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $5, 0);
1220 $$->gotid = TRUE;
1221 $$->gottype = TRUE;
1222 $$->gotstate = TRUE;
1223 if($2) free($2);
1224 if($4) free($4);
1226 | ',' e_expr ',' e_expr ',' expr {
1227 $$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $6, 0);
1228 $$->gotid = TRUE;
1229 $$->gottype = TRUE;
1230 $$->gotstate = TRUE;
1231 if($2) free($2);
1232 if($4) free($4);
1236 itemex_p_options
1237 : /* Empty */ { $$ = new_itemex_opt(0, 0, 0, 0); }
1238 | ',' expr {
1239 $$ = new_itemex_opt($2, 0, 0, 0);
1240 $$->gotid = TRUE;
1242 | ',' e_expr ',' expr {
1243 $$ = new_itemex_opt($2 ? *($2) : 0, $4, 0, 0);
1244 if($2) free($2);
1245 $$->gotid = TRUE;
1246 $$->gottype = TRUE;
1248 | ',' e_expr ',' e_expr ',' expr {
1249 $$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $6, 0);
1250 if($2) free($2);
1251 if($4) free($4);
1252 $$->gotid = TRUE;
1253 $$->gottype = TRUE;
1254 $$->gotstate = TRUE;
1256 | ',' e_expr ',' e_expr ',' e_expr ',' expr {
1257 $$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $6 ? *($6) : 0, $8);
1258 if($2) free($2);
1259 if($4) free($4);
1260 if($6) free($6);
1261 $$->gotid = TRUE;
1262 $$->gottype = TRUE;
1263 $$->gotstate = TRUE;
1264 $$->gothelpid = TRUE;
1268 /* ------------------------------ StringTable ------------------------------ */
1269 /* Stringtables are parsed differently than other resources because their
1270 * layout is substantially different from other resources.
1271 * The table is parsed through a _global_ variable 'tagstt' which holds the
1272 * current stringtable descriptor (stringtable_t *) and 'sttres' that holds a
1273 * list of stringtables of different languages.
1275 stringtable
1276 : stt_head tBEGIN strings tEND {
1277 if(!$3)
1279 yyerror("Stringtable must have at least one entry");
1281 else
1283 stringtable_t *stt;
1284 /* Check if we added to a language table or created
1285 * a new one.
1287 for(stt = sttres; stt; stt = stt->next)
1289 if(stt == tagstt)
1290 break;
1292 if(!stt)
1294 /* It is a new one */
1295 if(sttres)
1297 sttres->prev = tagstt;
1298 tagstt->next = sttres;
1299 sttres = tagstt;
1301 else
1302 sttres = tagstt;
1304 /* Else were done */
1306 if(tagstt_memopt)
1308 free(tagstt_memopt);
1309 tagstt_memopt = NULL;
1312 $$ = tagstt;
1316 /* This is to get the language of the currently parsed stringtable */
1317 stt_head: STRINGTABLE loadmemopts opt_lvc {
1318 if((tagstt = find_stringtable($3)) == NULL)
1319 tagstt = new_stringtable($3);
1320 tagstt_memopt = $2;
1321 tagstt_version = $3->version;
1322 tagstt_characts = $3->characts;
1323 if($3)
1324 free($3);
1328 strings : /* Empty */ { $$ = NULL; }
1329 | strings expr opt_comma tSTRING {
1330 int i;
1331 assert(tagstt != NULL);
1332 if($2 > 65535 || $2 < -32768)
1333 yyerror("Stringtable entry's ID out of range (%d)", $2);
1334 /* Search for the ID */
1335 for(i = 0; i < tagstt->nentries; i++)
1337 if(tagstt->entries[i].id == $2)
1338 yyerror("Stringtable ID %d already in use", $2);
1340 /* If we get here, then we have a new unique entry */
1341 tagstt->nentries++;
1342 tagstt->entries = xrealloc(tagstt->entries, sizeof(tagstt->entries[0]) * tagstt->nentries);
1343 tagstt->entries[tagstt->nentries-1].id = $2;
1344 tagstt->entries[tagstt->nentries-1].str = $4;
1345 if(tagstt_memopt)
1346 tagstt->entries[tagstt->nentries-1].memopt = *tagstt_memopt;
1347 else
1348 tagstt->entries[tagstt->nentries-1].memopt = WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE;
1349 tagstt->entries[tagstt->nentries-1].version = tagstt_version;
1350 tagstt->entries[tagstt->nentries-1].characts = tagstt_characts;
1352 if(!win32 && $4->size > 254)
1353 yyerror("Stringtable entry more than 254 characters");
1354 if(win32 && $4->size > 65534) /* Hmm..., does this happen? */
1355 yyerror("Stringtable entry more than 65534 characters (probably something else that went wrong)");
1356 $$ = tagstt;
1360 opt_comma /* There seem to be two ways to specify a stringtable... */
1361 : /* Empty */
1362 | ','
1365 /* ------------------------------ VersionInfo ------------------------------ */
1366 versioninfo
1367 : VERSIONINFO fix_version tBEGIN ver_blocks tEND {
1368 $$ = $2;
1369 $2->blocks = get_ver_block_head($4);
1373 fix_version
1374 : /* Empty */ { $$ = new_versioninfo(); }
1375 | fix_version FILEVERSION expr ',' expr ',' expr ',' expr {
1376 if($1->gotit.fv)
1377 yyerror("FILEVERSION already defined");
1378 $$ = $1;
1379 $$->filever_maj1 = $3;
1380 $$->filever_maj2 = $5;
1381 $$->filever_min1 = $7;
1382 $$->filever_min2 = $9;
1383 $$->gotit.fv = 1;
1385 | fix_version PRODUCTVERSION expr ',' expr ',' expr ',' expr {
1386 if($1->gotit.pv)
1387 yyerror("PRODUCTVERSION already defined");
1388 $$ = $1;
1389 $$->prodver_maj1 = $3;
1390 $$->prodver_maj2 = $5;
1391 $$->prodver_min1 = $7;
1392 $$->prodver_min2 = $9;
1393 $$->gotit.pv = 1;
1395 | fix_version FILEFLAGS expr {
1396 if($1->gotit.ff)
1397 yyerror("FILEFLAGS already defined");
1398 $$ = $1;
1399 $$->fileflags = $3;
1400 $$->gotit.ff = 1;
1402 | fix_version FILEFLAGSMASK expr {
1403 if($1->gotit.ffm)
1404 yyerror("FILEFLAGSMASK already defined");
1405 $$ = $1;
1406 $$->fileflagsmask = $3;
1407 $$->gotit.ffm = 1;
1409 | fix_version FILEOS expr {
1410 if($1->gotit.fo)
1411 yyerror("FILEOS already defined");
1412 $$ = $1;
1413 $$->fileos = $3;
1414 $$->gotit.fo = 1;
1416 | fix_version FILETYPE expr {
1417 if($1->gotit.ft)
1418 yyerror("FILETYPE already defined");
1419 $$ = $1;
1420 $$->filetype = $3;
1421 $$->gotit.ft = 1;
1423 | fix_version FILESUBTYPE expr {
1424 if($1->gotit.fst)
1425 yyerror("FILESUBTYPE already defined");
1426 $$ = $1;
1427 $$->filesubtype = $3;
1428 $$->gotit.fst = 1;
1432 ver_blocks
1433 : /* Empty */ { $$ = NULL; }
1434 | ver_blocks ver_block {
1435 $$ = $2;
1436 $$->prev = $1;
1437 if($1)
1438 $1->next = $$;
1442 ver_block
1443 : BLOCK tSTRING tBEGIN ver_values tEND {
1444 $$ = new_ver_block();
1445 $$->name = $2;
1446 $$->values = get_ver_value_head($4);
1450 ver_values
1451 : /* Empty */ { $$ = NULL; }
1452 | ver_values ver_value {
1453 $$ = $2;
1454 $$->prev = $1;
1455 if($1)
1456 $1->next = $$;
1460 ver_value
1461 : ver_block {
1462 $$ = new_ver_value();
1463 $$->type = val_block;
1464 $$->value.block = $1;
1466 | VALUE tSTRING ',' tSTRING {
1467 $$ = new_ver_value();
1468 $$->type = val_str;
1469 $$->key = $2;
1470 $$->value.str = $4;
1472 | VALUE tSTRING ',' ver_words {
1473 $$ = new_ver_value();
1474 $$->type = val_words;
1475 $$->key = $2;
1476 $$->value.words = $4;
1480 ver_words
1481 : expr { $$ = new_ver_words($1); }
1482 | ver_words ',' expr { $$ = add_ver_words($1, $3); }
1485 /* ------------------------------ Toolbar ------------------------------ */
1486 toolbar: TOOLBAR loadmemopts expr ',' expr opt_lvc tBEGIN toolbar_items tEND {
1487 int nitems;
1488 toolbar_item_t *items = get_tlbr_buttons_head($8, &nitems);
1489 $$ = new_toolbar($3, $5, items, nitems);
1490 if($2)
1492 $$->memopt = *($2);
1493 free($2);
1495 else
1497 $$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
1499 if($6)
1501 $$->lvc = *($6);
1502 free($6);
1504 if(!$$->lvc.language)
1506 $$->lvc.language = dup_language(currentlanguage);
1511 toolbar_items
1512 : /* Empty */ { $$ = NULL; }
1513 | toolbar_items BUTTON expr {
1514 toolbar_item_t *idrec = new_toolbar_item();
1515 idrec->id = $3;
1516 $$ = ins_tlbr_button($1, idrec);
1518 | toolbar_items SEPARATOR {
1519 toolbar_item_t *idrec = new_toolbar_item();
1520 idrec->id = 0;
1521 $$ = ins_tlbr_button($1, idrec);
1525 /* ------------------------------ Memory options ------------------------------ */
1526 loadmemopts
1527 : /* Empty */ { $$ = NULL; }
1528 | loadmemopts lamo {
1529 if($1)
1531 *($1) |= *($2);
1532 $$ = $1;
1533 free($2);
1535 else
1536 $$ = $2;
1538 | loadmemopts lama {
1539 if($1)
1541 *($1) &= *($2);
1542 $$ = $1;
1543 free($2);
1545 else
1547 *$2 &= WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE;
1548 $$ = $2;
1553 lamo : PRELOAD { $$ = new_int(WRC_MO_PRELOAD); }
1554 | MOVEABLE { $$ = new_int(WRC_MO_MOVEABLE); }
1555 | DISCARDABLE { $$ = new_int(WRC_MO_DISCARDABLE); }
1556 | tPURE { $$ = new_int(WRC_MO_PURE); }
1559 lama : LOADONCALL { $$ = new_int(~WRC_MO_PRELOAD); }
1560 | tFIXED { $$ = new_int(~WRC_MO_MOVEABLE); }
1561 | IMPURE { $$ = new_int(~WRC_MO_PURE); }
1564 /* ------------------------------ Win32 options ------------------------------ */
1565 opt_lvc : /* Empty */ { $$ = new_lvc(); }
1566 | opt_lvc opt_language {
1567 if(!win32)
1568 yywarning("LANGUAGE not supported in 16-bit mode");
1569 if($1->language)
1570 yyerror("Language already defined");
1571 $$ = $1;
1572 $1->language = $2;
1574 | opt_lvc opt_characts {
1575 if(!win32)
1576 yywarning("CHARACTERISTICS not supported in 16-bit mode");
1577 if($1->characts)
1578 yyerror("Characteristics already defined");
1579 $$ = $1;
1580 $1->characts = $2;
1582 | opt_lvc opt_version {
1583 if(!win32)
1584 yywarning("VERSION not supported in 16-bit mode");
1585 if($1->version)
1586 yyerror("Version already defined");
1587 $$ = $1;
1588 $1->version = $2;
1592 opt_language
1593 : LANGUAGE expr ',' expr { $$ = new_language($2, $4); }
1596 opt_characts
1597 : CHARACTERISTICS expr { $$ = new_characts($2); }
1600 opt_version
1601 : VERSION expr { $$ = new_version($2); }
1604 /* ------------------------------ Raw data handking ------------------------------ */
1605 raw_data: tBEGIN raw_elements tEND { $$ = $2; }
1608 raw_elements
1609 : RAWDATA { $$ = $1; }
1610 | NUMBER { $$ = int2raw_data($1); }
1611 | LNUMBER { $$ = long2raw_data($1); }
1612 | tSTRING { $$ = str2raw_data($1); }
1613 | raw_elements opt_comma RAWDATA { $$ = merge_raw_data($1, $3); free($3->data); free($3); }
1614 | raw_elements opt_comma NUMBER { $$ = merge_raw_data_int($1, $3); }
1615 | raw_elements opt_comma LNUMBER { $$ = merge_raw_data_long($1, $3); }
1616 | raw_elements opt_comma tSTRING { $$ = merge_raw_data_str($1, $3); }
1619 /* ------------------------------ Win32 expressions ------------------------------ */
1620 /* All win16 numbers are also handled here. This is inconsistent with MS'
1621 * resource compiler, but what the heck, its just handy to have.
1623 e_expr : /* Empty */ { $$ = 0; }
1624 | expr { $$ = new_int($1); }
1626 expr : xpr { $$ = ($1); }
1629 xpr : xpr '+' xpr { $$ = ($1) + ($3); }
1630 | xpr '-' xpr { $$ = ($1) - ($3); }
1631 | xpr '|' xpr { $$ = ($1) | ($3); }
1632 | xpr '&' xpr { $$ = ($1) & ($3); }
1633 | xpr '*' xpr { $$ = ($1) * ($3); }
1634 | xpr '/' xpr { $$ = ($1) / ($3); }
1635 | '~' xpr { $$ = ~($2); }
1636 | '-' xpr { $$ = -($2); } /* FIXME: shift/reduce conflict */
1637 /* | '+' xpr { $$ = $2; } */
1638 | '(' xpr ')' { $$ = $2; }
1639 | any_num { $$ = $1; want_rscname = 0; }
1640 | NOT any_num { $$ = ~($2); }
1643 any_num : NUMBER { $$ = $1; }
1644 | LNUMBER { $$ = $1; }
1648 /* Dialog specific functions */
1649 dialog_t *dialog_style(style_t * st, dialog_t *dlg)
1651 assert(dlg != NULL);
1652 if(dlg->style == NULL)
1654 dlg->style = new_style(0,0);
1657 if(dlg->gotstyle)
1659 yywarning("Style already defined, or-ing together");
1661 else
1663 dlg->style->or_mask = 0;
1664 dlg->style->and_mask = 0;
1666 dlg->style->or_mask |= st->or_mask;
1667 dlg->style->and_mask |= st->and_mask;
1668 dlg->gotstyle = TRUE;
1669 free(st);
1670 return dlg;
1673 dialog_t *dialog_exstyle(style_t *st, dialog_t *dlg)
1675 assert(dlg != NULL);
1676 if(dlg->exstyle == NULL)
1678 dlg->exstyle = new_style(0,0);
1681 if(dlg->gotexstyle)
1683 yywarning("ExStyle already defined, or-ing together");
1685 else
1687 dlg->exstyle->or_mask = 0;
1688 dlg->exstyle->and_mask = 0;
1690 dlg->exstyle->or_mask |= st->or_mask;
1691 dlg->exstyle->and_mask |= st->and_mask;
1692 dlg->gotexstyle = TRUE;
1693 free(st);
1694 return dlg;
1697 dialog_t *dialog_caption(string_t *s, dialog_t *dlg)
1699 assert(dlg != NULL);
1700 if(dlg->title)
1701 yyerror("Caption already defined");
1702 dlg->title = s;
1703 return dlg;
1706 dialog_t *dialog_font(font_id_t *f, dialog_t *dlg)
1708 assert(dlg != NULL);
1709 if(dlg->font)
1710 yyerror("Font already defined");
1711 dlg->font = f;
1712 return dlg;
1715 dialog_t *dialog_class(name_id_t *n, dialog_t *dlg)
1717 assert(dlg != NULL);
1718 if(dlg->dlgclass)
1719 yyerror("Class already defined");
1720 dlg->dlgclass = n;
1721 return dlg;
1724 dialog_t *dialog_menu(name_id_t *m, dialog_t *dlg)
1726 assert(dlg != NULL);
1727 if(dlg->menu)
1728 yyerror("Menu already defined");
1729 dlg->menu = m;
1730 return dlg;
1733 dialog_t *dialog_language(language_t *l, dialog_t *dlg)
1735 assert(dlg != NULL);
1736 if(dlg->lvc.language)
1737 yyerror("Language already defined");
1738 dlg->lvc.language = l;
1739 return dlg;
1742 dialog_t *dialog_characteristics(characts_t *c, dialog_t *dlg)
1744 assert(dlg != NULL);
1745 if(dlg->lvc.characts)
1746 yyerror("Characteristics already defined");
1747 dlg->lvc.characts = c;
1748 return dlg;
1751 dialog_t *dialog_version(version_t *v, dialog_t *dlg)
1753 assert(dlg != NULL);
1754 if(dlg->lvc.version)
1755 yyerror("Version already defined");
1756 dlg->lvc.version = v;
1757 return dlg;
1760 /* Controls specific functions */
1761 control_t *ins_ctrl(int type, int special_style, control_t *ctrl, control_t *prev)
1763 /* Hm... this seems to be jammed in at all time... */
1764 int defaultstyle = WS_CHILD | WS_VISIBLE;
1766 assert(ctrl != NULL);
1767 ctrl->prev = prev;
1769 if(prev)
1770 prev->next = ctrl;
1772 if(type != -1)
1774 ctrl->ctlclass = new_name_id();
1775 ctrl->ctlclass->type = name_ord;
1776 ctrl->ctlclass->name.i_name = type;
1779 switch(type)
1781 case CT_BUTTON:
1782 if(special_style != BS_GROUPBOX && special_style != BS_RADIOBUTTON)
1783 defaultstyle |= WS_TABSTOP;
1784 break;
1785 case CT_EDIT:
1786 defaultstyle |= WS_TABSTOP | WS_BORDER;
1787 break;
1788 case CT_LISTBOX:
1789 defaultstyle |= LBS_NOTIFY | WS_BORDER;
1790 break;
1791 case CT_COMBOBOX:
1792 defaultstyle |= CBS_SIMPLE;
1793 break;
1794 case CT_STATIC:
1795 if(special_style == SS_CENTER || special_style == SS_LEFT || special_style == SS_RIGHT)
1796 defaultstyle |= WS_GROUP;
1797 break;
1800 if(!ctrl->gotstyle) /* Handle default style setting */
1802 switch(type)
1804 case CT_EDIT:
1805 defaultstyle |= ES_LEFT;
1806 break;
1807 case CT_LISTBOX:
1808 defaultstyle |= LBS_NOTIFY;
1809 break;
1810 case CT_COMBOBOX:
1811 defaultstyle |= CBS_SIMPLE | WS_TABSTOP;
1812 break;
1813 case CT_SCROLLBAR:
1814 defaultstyle |= SBS_HORZ;
1815 break;
1816 case CT_BUTTON:
1817 switch(special_style)
1819 case BS_CHECKBOX:
1820 case BS_DEFPUSHBUTTON:
1821 case BS_PUSHBUTTON:
1822 case BS_GROUPBOX:
1823 /* case BS_PUSHBOX: */
1824 case BS_AUTORADIOBUTTON:
1825 case BS_AUTO3STATE:
1826 case BS_3STATE:
1827 case BS_AUTOCHECKBOX:
1828 defaultstyle |= WS_TABSTOP;
1829 break;
1830 default:
1831 yywarning("Unknown default button control-style 0x%08x", special_style);
1832 case BS_RADIOBUTTON:
1833 break;
1835 break;
1837 case CT_STATIC:
1838 switch(special_style)
1840 case SS_LEFT:
1841 case SS_RIGHT:
1842 case SS_CENTER:
1843 defaultstyle |= WS_GROUP;
1844 break;
1845 case SS_ICON: /* Special case */
1846 break;
1847 default:
1848 yywarning("Unknown default static control-style 0x%08x", special_style);
1849 break;
1851 break;
1852 case -1: /* Generic control */
1853 goto byebye;
1855 default:
1856 yyerror("Internal error (report this): Got weird control type 0x%08x", type);
1860 /* The SS_ICON flag is always forced in for icon controls */
1861 if(type == CT_STATIC && special_style == SS_ICON)
1862 defaultstyle |= SS_ICON;
1864 if (!ctrl->gotstyle)
1865 ctrl->style = new_style(0,0);
1867 /* combine all styles */
1868 ctrl->style->or_mask = ctrl->style->or_mask | defaultstyle | special_style;
1869 ctrl->gotstyle = TRUE;
1870 byebye:
1871 /* combine with NOT mask */
1872 if (ctrl->gotstyle)
1874 ctrl->style->or_mask &= ~(ctrl->style->and_mask);
1875 ctrl->style->and_mask = 0;
1877 if (ctrl->gotexstyle)
1879 ctrl->exstyle->or_mask &= ~(ctrl->exstyle->and_mask);
1880 ctrl->exstyle->and_mask = 0;
1882 return ctrl;
1885 name_id_t *convert_ctlclass(name_id_t *cls)
1887 char *cc;
1888 int iclass;
1890 if(cls->type == name_ord)
1891 return cls;
1892 assert(cls->type == name_str);
1893 if(cls->type == str_unicode)
1895 yyerror("Don't yet support unicode class comparison");
1897 else
1898 cc = cls->name.s_name->str.cstr;
1900 if(!strcasecmp("BUTTON", cc))
1901 iclass = CT_BUTTON;
1902 else if(!strcasecmp("COMBOBOX", cc))
1903 iclass = CT_COMBOBOX;
1904 else if(!strcasecmp("LISTBOX", cc))
1905 iclass = CT_LISTBOX;
1906 else if(!strcasecmp("EDIT", cc))
1907 iclass = CT_EDIT;
1908 else if(!strcasecmp("STATIC", cc))
1909 iclass = CT_STATIC;
1910 else if(!strcasecmp("SCROLLBAR", cc))
1911 iclass = CT_SCROLLBAR;
1912 else
1913 return cls; /* No default, return user controlclass */
1915 free(cls->name.s_name->str.cstr);
1916 free(cls->name.s_name);
1917 cls->type = name_ord;
1918 cls->name.i_name = iclass;
1919 return cls;
1922 /* DialogEx specific functions */
1923 dialogex_t *dialogex_style(style_t * st, dialogex_t *dlg)
1925 assert(dlg != NULL);
1926 if(dlg->style == NULL)
1928 dlg->style = new_style(0,0);
1931 if(dlg->gotstyle)
1933 yywarning("Style already defined, or-ing together");
1935 else
1937 dlg->style->or_mask = 0;
1938 dlg->style->and_mask = 0;
1940 dlg->style->or_mask |= st->or_mask;
1941 dlg->style->and_mask |= st->and_mask;
1942 dlg->gotstyle = TRUE;
1943 free(st);
1944 return dlg;
1947 dialogex_t *dialogex_exstyle(style_t * st, dialogex_t *dlg)
1949 assert(dlg != NULL);
1950 if(dlg->exstyle == NULL)
1952 dlg->exstyle = new_style(0,0);
1955 if(dlg->gotexstyle)
1957 yywarning("ExStyle already defined, or-ing together");
1959 else
1961 dlg->exstyle->or_mask = 0;
1962 dlg->exstyle->and_mask = 0;
1964 dlg->exstyle->or_mask |= st->or_mask;
1965 dlg->exstyle->and_mask |= st->and_mask;
1966 dlg->gotexstyle = TRUE;
1967 free(st);
1968 return dlg;
1971 dialogex_t *dialogex_caption(string_t *s, dialogex_t *dlg)
1973 assert(dlg != NULL);
1974 if(dlg->title)
1975 yyerror("Caption already defined");
1976 dlg->title = s;
1977 return dlg;
1980 dialogex_t *dialogex_font(font_id_t *f, dialogex_t *dlg)
1982 assert(dlg != NULL);
1983 if(dlg->font)
1984 yyerror("Font already defined");
1985 dlg->font = f;
1986 return dlg;
1989 dialogex_t *dialogex_class(name_id_t *n, dialogex_t *dlg)
1991 assert(dlg != NULL);
1992 if(dlg->dlgclass)
1993 yyerror("Class already defined");
1994 dlg->dlgclass = n;
1995 return dlg;
1998 dialogex_t *dialogex_menu(name_id_t *m, dialogex_t *dlg)
2000 assert(dlg != NULL);
2001 if(dlg->menu)
2002 yyerror("Menu already defined");
2003 dlg->menu = m;
2004 return dlg;
2007 dialogex_t *dialogex_language(language_t *l, dialogex_t *dlg)
2009 assert(dlg != NULL);
2010 if(dlg->lvc.language)
2011 yyerror("Language already defined");
2012 dlg->lvc.language = l;
2013 return dlg;
2016 dialogex_t *dialogex_characteristics(characts_t *c, dialogex_t *dlg)
2018 assert(dlg != NULL);
2019 if(dlg->lvc.characts)
2020 yyerror("Characteristics already defined");
2021 dlg->lvc.characts = c;
2022 return dlg;
2025 dialogex_t *dialogex_version(version_t *v, dialogex_t *dlg)
2027 assert(dlg != NULL);
2028 if(dlg->lvc.version)
2029 yyerror("Version already defined");
2030 dlg->lvc.version = v;
2031 return dlg;
2034 /* Accelerator specific functions */
2035 event_t *add_event(int key, int id, int flags, event_t *prev)
2037 event_t *ev = new_event();
2039 if((flags & (WRC_AF_VIRTKEY | WRC_AF_ASCII)) == (WRC_AF_VIRTKEY | WRC_AF_ASCII))
2040 yyerror("Cannot use both ASCII and VIRTKEY");
2042 ev->key = key;
2043 ev->id = id;
2044 ev->flags = flags & ~WRC_AF_ASCII;
2045 ev->prev = prev;
2046 if(prev)
2047 prev->next = ev;
2048 return ev;
2051 event_t *add_string_event(string_t *key, int id, int flags, event_t *prev)
2053 int keycode = 0;
2054 event_t *ev = new_event();
2056 if(key->type != str_char)
2057 yyerror("Key code must be an ascii string");
2059 if((flags & WRC_AF_VIRTKEY) && (!isupper(key->str.cstr[0]) && !isdigit(key->str.cstr[0])))
2060 yyerror("VIRTKEY code is not equal to ascii value");
2062 if(key->str.cstr[0] == '^' && (flags & WRC_AF_CONTROL) != 0)
2064 yyerror("Cannot use both '^' and CONTROL modifier");
2066 else if(key->str.cstr[0] == '^')
2068 keycode = toupper(key->str.cstr[1]) - '@';
2069 if(keycode >= ' ')
2070 yyerror("Control-code out of range");
2072 else
2073 keycode = key->str.cstr[0];
2074 ev->key = keycode;
2075 ev->id = id;
2076 ev->flags = flags & ~WRC_AF_ASCII;
2077 ev->prev = prev;
2078 if(prev)
2079 prev->next = ev;
2080 return ev;
2083 /* MenuEx specific functions */
2084 itemex_opt_t *new_itemex_opt(int id, int type, int state, int helpid)
2086 itemex_opt_t *opt = (itemex_opt_t *)xmalloc(sizeof(itemex_opt_t));
2087 opt->id = id;
2088 opt->type = type;
2089 opt->state = state;
2090 opt->helpid = helpid;
2091 return opt;
2094 /* Raw data functions */
2095 raw_data_t *load_file(string_t *name)
2097 FILE *fp;
2098 raw_data_t *rd;
2099 if(name->type != str_char)
2100 yyerror("Filename must be ASCII string");
2102 fp = open_include(name->str.cstr, 1);
2103 if(!fp)
2104 yyerror("Cannot open file %s", name->str.cstr);
2105 rd = new_raw_data();
2106 fseek(fp, 0, SEEK_END);
2107 rd->size = ftell(fp);
2108 fseek(fp, 0, SEEK_SET);
2109 rd->data = (char *)xmalloc(rd->size);
2110 fread(rd->data, rd->size, 1, fp);
2111 fclose(fp);
2112 HEAPCHECK();
2113 return rd;
2116 raw_data_t *int2raw_data(int i)
2118 raw_data_t *rd;
2120 if((int)((short)i) != i)
2121 yywarning("Integer constant out of 16bit range (%d), truncated to %d\n", i, (short)i);
2123 rd = new_raw_data();
2124 rd->size = sizeof(short);
2125 rd->data = (char *)xmalloc(rd->size);
2126 *(short *)(rd->data) = (short)i;
2127 return rd;
2130 raw_data_t *long2raw_data(int i)
2132 raw_data_t *rd;
2133 rd = new_raw_data();
2134 rd->size = sizeof(int);
2135 rd->data = (char *)xmalloc(rd->size);
2136 *(int *)(rd->data) = i;
2137 return rd;
2140 raw_data_t *str2raw_data(string_t *str)
2142 raw_data_t *rd;
2143 rd = new_raw_data();
2144 rd->size = str->size * (str->type == str_char ? 1 : 2);
2145 rd->data = (char *)xmalloc(rd->size);
2146 memcpy(rd->data, str->str.cstr, rd->size);
2147 return rd;
2150 raw_data_t *merge_raw_data(raw_data_t *r1, raw_data_t *r2)
2152 r1->data = xrealloc(r1->data, r1->size + r2->size);
2153 memcpy(r1->data + r1->size, r2->data, r2->size);
2154 r1->size += r2->size;
2155 return r1;
2158 raw_data_t *merge_raw_data_int(raw_data_t *r1, int i)
2160 raw_data_t *t = int2raw_data(i);
2161 merge_raw_data(r1, t);
2162 free(t->data);
2163 free(t);
2164 return r1;
2167 raw_data_t *merge_raw_data_long(raw_data_t *r1, int i)
2169 raw_data_t *t = long2raw_data(i);
2170 merge_raw_data(r1, t);
2171 free(t->data);
2172 free(t);
2173 return r1;
2176 raw_data_t *merge_raw_data_str(raw_data_t *r1, string_t *str)
2178 raw_data_t *t = str2raw_data(str);
2179 merge_raw_data(r1, t);
2180 free(t->data);
2181 free(t);
2182 return r1;
2185 /* Function the go back in a list to get the head */
2186 menu_item_t *get_item_head(menu_item_t *p)
2188 if(!p)
2189 return NULL;
2190 while(p->prev)
2191 p = p->prev;
2192 return p;
2195 menuex_item_t *get_itemex_head(menuex_item_t *p)
2197 if(!p)
2198 return NULL;
2199 while(p->prev)
2200 p = p->prev;
2201 return p;
2204 resource_t *get_resource_head(resource_t *p)
2206 if(!p)
2207 return NULL;
2208 while(p->prev)
2209 p = p->prev;
2210 return p;
2213 ver_block_t *get_ver_block_head(ver_block_t *p)
2215 if(!p)
2216 return NULL;
2217 while(p->prev)
2218 p = p->prev;
2219 return p;
2222 ver_value_t *get_ver_value_head(ver_value_t *p)
2224 if(!p)
2225 return NULL;
2226 while(p->prev)
2227 p = p->prev;
2228 return p;
2231 control_t *get_control_head(control_t *p)
2233 if(!p)
2234 return NULL;
2235 while(p->prev)
2236 p = p->prev;
2237 return p;
2240 event_t *get_event_head(event_t *p)
2242 if(!p)
2243 return NULL;
2244 while(p->prev)
2245 p = p->prev;
2246 return p;
2249 /* Find a stringtable with given language */
2250 stringtable_t *find_stringtable(lvc_t *lvc)
2252 stringtable_t *stt;
2254 assert(lvc != NULL);
2256 if(!lvc->language)
2257 lvc->language = dup_language(currentlanguage);
2259 for(stt = sttres; stt; stt = stt->next)
2261 if(stt->lvc.language->id == lvc->language->id
2262 && stt->lvc.language->id == lvc->language->id)
2264 /* Found a table with the same language */
2265 /* The version and characteristics are now handled
2266 * in the generation of the individual stringtables.
2267 * This enables localized analysis.
2268 if((stt->lvc.version && lvc->version && *(stt->lvc.version) != *(lvc->version))
2269 || (!stt->lvc.version && lvc->version)
2270 || (stt->lvc.version && !lvc->version))
2271 yywarning("Stringtable's versions are not the same, using first definition");
2273 if((stt->lvc.characts && lvc->characts && *(stt->lvc.characts) != *(lvc->characts))
2274 || (!stt->lvc.characts && lvc->characts)
2275 || (stt->lvc.characts && !lvc->characts))
2276 yywarning("Stringtable's characteristics are not the same, using first definition");
2278 return stt;
2281 return NULL;
2284 /* qsort sorting function for string table entries */
2285 #define STE(p) ((stt_entry_t *)(p))
2286 int sort_stt_entry(const void *e1, const void *e2)
2288 return STE(e1)->id - STE(e2)->id;
2290 #undef STE
2292 resource_t *build_stt_resources(stringtable_t *stthead)
2294 stringtable_t *stt;
2295 stringtable_t *newstt;
2296 resource_t *rsc;
2297 resource_t *rsclist = NULL;
2298 resource_t *rsctail = NULL;
2299 int i;
2300 int j;
2301 DWORD andsum;
2302 DWORD orsum;
2303 characts_t *characts;
2304 version_t *version;
2306 if(!stthead)
2307 return NULL;
2309 /* For all languages defined */
2310 for(stt = stthead; stt; stt = stt->next)
2312 assert(stt->nentries > 0);
2314 /* Sort the entries */
2315 if(stt->nentries > 1)
2316 qsort(stt->entries, stt->nentries, sizeof(stt->entries[0]), sort_stt_entry);
2318 for(i = 0; i < stt->nentries; )
2320 newstt = new_stringtable(&stt->lvc);
2321 newstt->entries = (stt_entry_t *)xmalloc(16 * sizeof(stt_entry_t));
2322 newstt->nentries = 16;
2323 newstt->idbase = stt->entries[i].id & ~0xf;
2324 for(j = 0; j < 16 && i < stt->nentries; j++)
2326 if(stt->entries[i].id - newstt->idbase == j)
2328 newstt->entries[j] = stt->entries[i];
2329 i++;
2332 andsum = ~0;
2333 orsum = 0;
2334 characts = NULL;
2335 version = NULL;
2336 /* Check individual memory options and get
2337 * the first characteristics/version
2339 for(j = 0; j < 16; j++)
2341 if(!newstt->entries[j].str)
2342 continue;
2343 andsum &= newstt->entries[j].memopt;
2344 orsum |= newstt->entries[j].memopt;
2345 if(!characts)
2346 characts = newstt->entries[j].characts;
2347 if(!version)
2348 version = newstt->entries[j].version;
2350 if(andsum != orsum)
2352 warning("Stringtable's memory options are not equal (idbase: %d)", newstt->idbase);
2354 /* Check version and characteristics */
2355 for(j = 0; j < 16; j++)
2357 if(characts
2358 && newstt->entries[j].characts
2359 && *newstt->entries[j].characts != *characts)
2360 warning("Stringtable's characteristics are not the same (idbase: %d)", newstt->idbase);
2361 if(version
2362 && newstt->entries[j].version
2363 && *newstt->entries[j].version != *version)
2364 warning("Stringtable's versions are not the same (idbase: %d)", newstt->idbase);
2366 rsc = new_resource(res_stt, newstt, newstt->memopt, newstt->lvc.language);
2367 rsc->name = new_name_id();
2368 rsc->name->type = name_ord;
2369 rsc->name->name.i_name = (newstt->idbase >> 4) + 1;
2370 rsc->memopt = andsum; /* Set to least common denominator */
2371 newstt->memopt = andsum;
2372 newstt->lvc.characts = characts;
2373 newstt->lvc.version = version;
2374 if(!rsclist)
2376 rsclist = rsc;
2377 rsctail = rsc;
2379 else
2381 rsctail->next = rsc;
2382 rsc->prev = rsctail;
2383 rsctail = rsc;
2387 return rsclist;
2390 /* Cursor and icon splitter functions */
2391 typedef struct {
2392 language_t lan;
2393 int id;
2394 } id_alloc_t;
2396 static int get_new_id(id_alloc_t **list, int *n, language_t *lan)
2398 int i;
2399 assert(lan != NULL);
2400 assert(list != NULL);
2401 assert(n != NULL);
2403 if(!*list)
2405 *list = (id_alloc_t *)xmalloc(sizeof(id_alloc_t));
2406 *n = 1;
2407 (*list)[0].lan = *lan;
2408 (*list)[0].id = 1;
2409 return 1;
2412 for(i = 0; i < *n; i++)
2414 if((*list)[i].lan.id == lan->id && (*list)[i].lan.sub == lan->sub)
2415 return ++((*list)[i].id);
2418 *list = (id_alloc_t *)xrealloc(*list, sizeof(id_alloc_t) * (*n+1));
2419 (*list)[*n].lan = *lan;
2420 (*list)[*n].id = 1;
2421 *n += 1;
2422 return 1;
2425 int alloc_icon_id(language_t *lan)
2427 static id_alloc_t *idlist = NULL;
2428 static int nid = 0;
2430 return get_new_id(&idlist, &nid, lan);
2433 int alloc_cursor_id(language_t *lan)
2435 static id_alloc_t *idlist = NULL;
2436 static int nid = 0;
2438 return get_new_id(&idlist, &nid, lan);
2441 #define BPTR(base) ((char *)(rd->data + (base)))
2442 #define WPTR(base) ((WORD *)(rd->data + (base)))
2443 #define DPTR(base) ((DWORD *)(rd->data + (base)))
2444 void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico)
2446 int cnt;
2447 int i;
2448 icon_dir_entry_t *ide;
2449 icon_t *ico;
2450 icon_t *list = NULL;
2452 /* FIXME: Distinguish between normal and animated icons (RIFF format) */
2453 if(WPTR(0)[1] != 1)
2454 yyerror("Icon resource data has invalid type id %d", WPTR(0)[1]);
2455 cnt = WPTR(0)[2];
2456 ide = (icon_dir_entry_t *)&(WPTR(0)[3]);
2457 for(i = 0; i < cnt; i++)
2459 ico = new_icon();
2460 ico->id = alloc_icon_id(icog->lvc.language);
2461 ico->lvc.language = dup_language(icog->lvc.language);
2462 if(ide[i].offset > rd->size
2463 || ide[i].offset + ide[i].ressize > rd->size)
2464 yyerror("Icon resource data corrupt");
2465 ico->width = ide[i].width;
2466 ico->height = ide[i].height;
2467 ico->nclr = ide[i].nclr;
2468 ico->planes = ide[i].planes;
2469 ico->bits = ide[i].bits;
2470 if(!ico->planes)
2472 /* Argh! They did not fill out the resdir structure */
2473 ico->planes = ((BITMAPINFOHEADER *)BPTR(ide[i].offset))->biPlanes;
2475 if(!ico->bits)
2477 /* Argh! They did not fill out the resdir structure */
2478 ico->bits = ((BITMAPINFOHEADER *)BPTR(ide[i].offset))->biBitCount;
2480 ico->data = new_raw_data();
2481 copy_raw_data(ico->data, rd, ide[i].offset, ide[i].ressize);
2482 if(!list)
2484 list = ico;
2486 else
2488 ico->next = list;
2489 list->prev = ico;
2490 list = ico;
2493 icog->iconlist = list;
2494 *nico = cnt;
2497 void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur)
2499 int cnt;
2500 int i;
2501 cursor_dir_entry_t *cde;
2502 cursor_t *cur;
2503 cursor_t *list = NULL;
2505 /* FIXME: Distinguish between normal and animated cursors (RIFF format)*/
2506 if(WPTR(0)[1] != 2)
2507 yyerror("Cursor resource data has invalid type id %d", WPTR(0)[1]);
2508 cnt = WPTR(0)[2];
2509 cde = (cursor_dir_entry_t *)&(WPTR(0)[3]);
2510 for(i = 0; i < cnt; i++)
2512 cur = new_cursor();
2513 cur->id = alloc_cursor_id(curg->lvc.language);
2514 cur->lvc.language = dup_language(curg->lvc.language);
2515 if(cde[i].offset > rd->size
2516 || cde[i].offset + cde[i].ressize > rd->size)
2517 yyerror("Cursor resource data corrupt");
2518 cur->width = cde[i].width;
2519 cur->height = cde[i].height;
2520 cur->nclr = cde[i].nclr;
2521 /* The next two are to support color cursors */
2522 cur->planes = ((BITMAPINFOHEADER *)BPTR(cde[i].offset))->biPlanes;
2523 cur->bits = ((BITMAPINFOHEADER *)BPTR(cde[i].offset))->biBitCount;
2524 if(!win32 && (cur->planes != 1 || cur->bits != 1))
2525 yywarning("Win16 cursor contains colors");
2526 cur->xhot = cde[i].xhot;
2527 cur->yhot = cde[i].yhot;
2528 cur->data = new_raw_data();
2529 copy_raw_data(cur->data, rd, cde[i].offset, cde[i].ressize);
2530 if(!list)
2532 list = cur;
2534 else
2536 cur->next = list;
2537 list->prev = cur;
2538 list = cur;
2541 curg->cursorlist = list;
2542 *ncur = cnt;
2545 #undef BPTR
2546 #undef WPTR
2547 #undef DPTR
2550 toolbar_item_t *ins_tlbr_button(toolbar_item_t *prev, toolbar_item_t *idrec)
2552 idrec->prev = prev;
2553 if(prev)
2554 prev->next = idrec;
2556 return idrec;
2559 toolbar_item_t *get_tlbr_buttons_head(toolbar_item_t *p, int *nitems)
2561 if(!p)
2563 *nitems = 0;
2564 return NULL;
2567 *nitems = 1;
2569 while(p->prev)
2571 (*nitems)++;
2572 p = p->prev;
2575 return p;