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