3 * Copyright 1994 Martin von Loewis
4 * Copyright 1998-2000 Bertho A. Stultiens (BS)
5 * 1999 Juergen Schmied (JS)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * 24-Jul-2000 BS - Made a fix for broken Berkeley yacc on
23 * non-terminals (see cjunk rule).
24 * 21-May-2000 BS - Partial implementation of font resources.
25 * - Corrected language propagation for binary
26 * resources such as bitmaps, icons, cursors,
27 * userres and rcdata. The language is now
28 * correct in .res files.
29 * - Fixed reading the resource name as ident,
30 * so that it may overlap keywords.
31 * 20-May-2000 BS - Implemented animated cursors and icons
33 * 30-Apr-2000 BS - Reintegration into the wine-tree
34 * 14-Jan-2000 BS - Redid the usertype resources so that they
36 * 02-Jan-2000 BS - Removed the preprocessor from the grammar
37 * except for the # command (line numbers).
39 * 06-Nov-1999 JS - see CHANGES
41 * 29-Dec-1998 AdH - Grammar and function extensions.
42 * grammar: TOOLBAR resources, Named ICONs in
44 * functions: semantic actions for the grammar
45 * changes, resource files can now be anywhere
46 * on the include path instead of just in the
49 * 20-Jun-1998 BS - Fixed a bug in load_file() where the name was not
50 * printed out correctly.
52 * 17-Jun-1998 BS - Fixed a bug in CLASS statement parsing which should
53 * also accept a tSTRING as argument.
55 * 25-May-1998 BS - Found out that I need to support language, version
56 * and characteristics in inline resources (bitmap,
57 * cursor, etc) but they can also be specified with
58 * a filename. This renders my filename-scanning scheme
59 * worthless. Need to build newline parsing to solve
61 * It will come with version 1.1.0 (sigh).
63 * 19-May-1998 BS - Started to build a builtin preprocessor
65 * 30-Apr-1998 BS - Redid the stringtable parsing/handling. My previous
66 * ideas had some serious flaws.
68 * 27-Apr-1998 BS - Removed a lot of dead comments and put it in a doc
71 * 21-Apr-1998 BS - Added correct behavior for cursors and icons.
72 * - This file is growing too big. It is time to strip
73 * things and put it in a support file.
75 * 19-Apr-1998 BS - Tagged the stringtable resource so that only one
76 * resource will be created. This because the table
77 * has a different layout than other resources. The
78 * table has to be sorted, and divided into smaller
79 * resource entries (see comment in source).
81 * 17-Apr-1998 BS - Almost all strings, including identifiers, are parsed
82 * as string_t which include unicode strings upon
84 * - Parser now emits a warning when compiling win32
85 * extensions in win16 mode.
87 * 16-Apr-1998 BS - Raw data elements are now *optionally* separated
88 * by commas. Read the comments in file sq2dq.l.
89 * - FIXME: there are instances in the source that rely
90 * on the fact that int==32bit and pointers are int size.
91 * - Fixed the conflict in menuex by changing a rule
92 * back into right recursion. See note in source.
93 * - UserType resources cannot have an expression as its
94 * typeclass. See note in source.
96 * 15-Apr-1998 BS - Changed all right recursion into left recursion to
97 * get reduction of the parsestack.
98 * This also helps communication between bison and flex.
99 * Main advantage is that the Empty rule gets reduced
100 * first, which is used to allocate/link things.
101 * It also added a shift/reduce conflict in the menuex
102 * handling, due to expression/option possibility,
103 * although not serious.
105 * 14-Apr-1998 BS - Redone almost the entire parser. We're not talking
106 * about making it more efficient, but readable (for me)
107 * and slightly easier to expand/change.
108 * This is done primarily by using more reduce states
109 * with many (intuitive) types for the various resource
111 * - Added expression handling for all resources where a
112 * number is accepted (not only for win32). Also added
113 * multiply and division (not MS compatible, but handy).
114 * Unary minus introduced a shift/reduce conflict, but
117 * 13-Apr-1998 BS - Reordered a lot of things
118 * - Made the source more readable
119 * - Added Win32 resource definitions
120 * - Corrected syntax problems with an old yacc (;)
121 * - Added extra comment about grammar
124 #include "wine/port.h"
135 #include "newstruc.h"
137 #include "wine/wpp.h"
144 int want_nl
= 0; /* Signal flex that we need the next newline */
145 int want_id
= 0; /* Signal flex that we need the next identifier */
146 static stringtable_t
*tagstt
; /* Stringtable tag.
147 * It is set while parsing a stringtable to one of
148 * the stringtables in the sttres list or a new one
149 * if the language was not parsed before.
151 static stringtable_t
*sttres
; /* Stringtable resources. This holds the list of
152 * stringtables with different lanuages
154 static int dont_want_id
= 0; /* See language parsing for details */
156 /* Set to the current options of the currently scanning stringtable */
157 static int *tagstt_memopt
;
158 static characts_t
*tagstt_characts
;
159 static version_t
*tagstt_version
;
161 static const char riff
[4] = "RIFF"; /* RIFF file magic for animated cursor/icon */
163 /* Prototypes of here defined functions */
164 static event_t
*get_event_head
(event_t
*p
);
165 static control_t
*get_control_head
(control_t
*p
);
166 static ver_value_t
*get_ver_value_head
(ver_value_t
*p
);
167 static ver_block_t
*get_ver_block_head
(ver_block_t
*p
);
168 static resource_t
*get_resource_head
(resource_t
*p
);
169 static menu_item_t
*get_item_head
(menu_item_t
*p
);
170 static raw_data_t
*merge_raw_data_str
(raw_data_t
*r1
, string_t
*str
);
171 static raw_data_t
*merge_raw_data_int
(raw_data_t
*r1
, int i
);
172 static raw_data_t
*merge_raw_data_long
(raw_data_t
*r1
, int i
);
173 static raw_data_t
*merge_raw_data
(raw_data_t
*r1
, raw_data_t
*r2
);
174 static raw_data_t
*str2raw_data
(string_t
*str
);
175 static raw_data_t
*int2raw_data
(int i
);
176 static raw_data_t
*long2raw_data
(int i
);
177 static raw_data_t
*load_file
(string_t
*name
, language_t
*lang
);
178 static itemex_opt_t
*new_itemex_opt
(int id
, int type
, int state
, int helpid
);
179 static event_t
*add_string_event
(string_t
*key
, int id
, int flags
, event_t
*prev
);
180 static event_t
*add_event
(int key
, int id
, int flags
, event_t
*prev
);
181 static name_id_t
*convert_ctlclass
(name_id_t
*cls
);
182 static control_t
*ins_ctrl
(int type
, int special_style
, control_t
*ctrl
, control_t
*prev
);
183 static dialog_t
*dialog_version
(version_t
*v
, dialog_t
*dlg
);
184 static dialog_t
*dialog_characteristics
(characts_t
*c
, dialog_t
*dlg
);
185 static dialog_t
*dialog_language
(language_t
*l
, dialog_t
*dlg
);
186 static dialog_t
*dialog_menu
(name_id_t
*m
, dialog_t
*dlg
);
187 static dialog_t
*dialog_class
(name_id_t
*n
, dialog_t
*dlg
);
188 static dialog_t
*dialog_font
(font_id_t
*f
, dialog_t
*dlg
);
189 static dialog_t
*dialog_caption
(string_t
*s
, dialog_t
*dlg
);
190 static dialog_t
*dialog_exstyle
(style_t
* st
, dialog_t
*dlg
);
191 static dialog_t
*dialog_style
(style_t
* st
, dialog_t
*dlg
);
192 static resource_t
*build_stt_resources
(stringtable_t
*stthead
);
193 static stringtable_t
*find_stringtable
(lvc_t
*lvc
);
194 static toolbar_item_t
*ins_tlbr_button
(toolbar_item_t
*prev
, toolbar_item_t
*idrec
);
195 static toolbar_item_t
*get_tlbr_buttons_head
(toolbar_item_t
*p
, int *nitems
);
196 static string_t
*make_filename
(string_t
*s
);
197 static resource_t
*build_fontdirs
(resource_t
*tail
);
198 static resource_t
*build_fontdir
(resource_t
**fnt
, int nfnt
);
199 static int rsrcid_to_token
(int lookahead
);
236 toolbar_item_t
*tlbarItems
;
238 style_pair_t
*styles
;
244 %token
<num
> tNUMBER tLNUMBER
245 %token
<str
> tSTRING tIDENT
246 %token
<raw
> tRAWDATA
247 %token tACCELERATORS tBITMAP tCURSOR tDIALOG tDIALOGEX tMENU tMENUEX tMESSAGETABLE
248 %token tRCDATA tVERSIONINFO tSTRINGTABLE tFONT tFONTDIR tICON tHTML
249 %token tAUTO3STATE tAUTOCHECKBOX tAUTORADIOBUTTON tCHECKBOX tDEFPUSHBUTTON
250 %token tPUSHBUTTON tRADIOBUTTON tSTATE3
/* PUSHBOX */
251 %token tGROUPBOX tCOMBOBOX tLISTBOX tSCROLLBAR
252 %token tCONTROL tEDITTEXT
253 %token tRTEXT tCTEXT tLTEXT
255 %token tSHIFT tALT tASCII tVIRTKEY tGRAYED tCHECKED tINACTIVE tNOINVERT
256 %token tPURE tIMPURE tDISCARDABLE tLOADONCALL tPRELOAD tFIXED tMOVEABLE
257 %token tCLASS tCAPTION tCHARACTERISTICS tEXSTYLE tSTYLE tVERSION tLANGUAGE
258 %token tFILEVERSION tPRODUCTVERSION tFILEFLAGSMASK tFILEOS tFILETYPE tFILEFLAGS tFILESUBTYPE
259 %token tMENUBARBREAK tMENUBREAK tMENUITEM tPOPUP tSEPARATOR
261 %token tTOOLBAR tBUTTON
272 %type
<res
> resource_file resource resources resource_definition
273 %type
<stt
> stringtable strings
276 %type
<acc
> accelerators
279 %type
<ani
> cursor icon
280 %type
<dlg
> dialog dlg_attributes dialogex dlgex_attribs
281 %type
<ctl
> ctrls gen_ctrl lab_ctrl ctrl_desc iconinfo
283 %type
<ctl
> exctrls gen_exctrl lab_exctrl exctrl_desc
286 %type
<raw
> raw_data raw_elements opt_data file_raw
287 %type
<veri
> versioninfo fix_version
288 %type
<verw
> ver_words
289 %type
<blk
> ver_blocks ver_block
290 %type
<val
> ver_values ver_value
291 %type
<men
> menu menuex
292 %type
<menitm
> item_definitions menu_body itemex_definitions menuex_body
293 %type
<exopt
> itemex_p_options itemex_options
294 %type
<msg
> messagetable
296 %type
<num
> item_options
297 %type
<nid
> nameid nameid_s ctlclass usertype
298 %type
<num
> acc_opt acc accs
299 %type
<iptr
> loadmemopts lamo lama
300 %type
<fntid
> opt_font opt_exfont opt_expr
302 %type
<lan
> opt_language
303 %type
<chars
> opt_characts
304 %type
<ver
> opt_version
307 %type
<tlbar
> toolbar
308 %type
<tlbarItems
> toolbar_items
309 %type
<dginit
> dlginit
310 %type
<styles
> optional_style_pair
319 resource_t
*rsc
, *head
;
320 /* First add stringtables to the resource-list */
321 rsc
= build_stt_resources
(sttres
);
322 /* 'build_stt_resources' returns a head and $1 is a tail */
331 /* Find the tail again */
332 while
($1 && $1->next
)
334 /* Now add any fontdirectory */
335 rsc
= build_fontdirs
($1);
336 /* 'build_fontdir' returns a head and $1 is a tail */
346 /* Final statements before we're done */
347 if
((head
= get_resource_head
($1)) != NULL
)
349 if
(resource_top
) /* append to existing resources */
351 resource_t
*tail
= resource_top
;
352 while
(tail
->next
) tail
= tail
->next
;
356 else resource_top
= head
;
362 /* Resources are put into a linked list */
364 : /* Empty */ { $$
= NULL
; want_id
= 1; }
365 | resources resource
{
368 resource_t
*tail
= $2;
369 resource_t
*head
= $2;
378 /* Check for duplicate identifiers */
381 resource_t
*rsc
= $1;
384 if
(rsc
->type
== head
->type
385 && rsc
->lan
->id
== head
->lan
->id
386 && rsc
->lan
->sub
== head
->lan
->sub
387 && !compare_name_id
(rsc
->name
, head
->name
)
388 && (rsc
->type
!= res_usr ||
!compare_name_id
(rsc
->res.usr
->type
,head
->res.usr
->type
)))
390 yyerror("Duplicate resource name '%s'", get_nameid_str
(rsc
->name
));
399 resource_t
*tail
= $1;
407 if
(!dont_want_id
) /* See comments in language parsing below */
412 * The following newline rule will never get reduced because we never
413 * get the tNL token, unless we explicitly set the 'want_nl'
414 * flag, which we don't.
415 * The *ONLY* reason for this to be here is because Berkeley
416 * yacc (byacc), at least version 1.9, has a bug.
417 * (identified in the generated parser on the second
419 * static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93";
421 * This extra rule fixes it.
422 * The problem is that the expression handling rule "expr: xpr"
423 * is not reduced on non-terminal tokens, defined above in the
424 * %token declarations. Token tNL is the only non-terminal that
425 * can occur. The error becomes visible in the language parsing
426 * rule below, which looks at the look-ahead token and tests it
427 * for tNL. However, byacc already generates an error upon reading
428 * the token instead of keeping it as a lookahead. The reason
429 * lies in the lack of a $default transition in the "expr : xpr . "
430 * state (currently state 25). It is probably omitted because tNL
431 * is a non-terminal and the state contains 2 s/r conflicts. The
432 * state enumerates all possible transitions instead of using a
433 * $default transition.
434 * All in all, it is a bug in byacc. (period)
440 /* Parse top level resource definitions etc. */
442 : expr usrcvt resource_definition
{
446 if
($1 > 65535 ||
$1 < -32768)
447 yyerror("Resource's ID out of range (%d)", $1);
448 $$
->name
= new_name_id
();
449 $$
->name
->type
= name_ord
;
450 $$
->name
->name.i_name
= $1;
451 chat
("Got %s (%d)\n", get_typename
($3), $$
->name
->name.i_name
);
454 | tIDENT usrcvt resource_definition
{
458 $$
->name
= new_name_id
();
459 $$
->name
->type
= name_str
;
460 $$
->name
->name.s_name
= $1;
461 chat
("Got %s (%s)\n", get_typename
($3), $$
->name
->name.s_name
->str.cstr
);
465 /* Don't do anything, stringtables are converted to
466 * resource_t structures when we are finished parsing and
467 * the final rule of the parser is reduced (see above)
470 chat
("Got STRINGTABLE\n");
472 | tLANGUAGE
{want_nl
= 1; } expr
',' expr
{
473 /* We *NEED* the newline to delimit the expression.
474 * Otherwise, we would not be able to set the next
475 * want_id anymore because of the token-lookahead.
477 * However, we can test the lookahead-token for
478 * being "non-expression" type, in which case we
479 * continue. Fortunately, tNL is the only token that
480 * will break expression parsing and is implicitly
481 * void, so we just remove it. This scheme makes it
482 * possible to do some (not all) fancy preprocessor
484 * BTW, we also need to make sure that the next
485 * reduction of 'resources' above will *not* set
486 * want_id because we already have a lookahead that
489 if
(yychar != YYEMPTY
&& yychar != tNL
)
493 yychar = YYEMPTY
; /* Could use 'yyclearin', but we already need the*/
494 /* direct access to yychar in rule 'usrcvt' below. */
495 else if
(yychar == tIDENT
)
496 parser_warning
("LANGUAGE statement not delimited with newline; next identifier might be wrong\n");
498 want_nl
= 0; /* We don't want it anymore if we didn't get it */
501 parser_warning
("LANGUAGE not supported in 16-bit mode\n");
502 free
(currentlanguage
);
503 if
(get_language_codepage
($3, $5) == -1)
504 yyerror( "Language %04x is not supported", ($5<<10) + $3);
505 currentlanguage
= new_language
($3, $5);
507 chat
("Got LANGUAGE %d,%d (0x%04x)\n", $3, $5, ($5<<10) + $3);
512 * Remapping of numerical resource types
513 * (see also comment of called function below)
515 usrcvt
: /* Empty */ { yychar = rsrcid_to_token
(yychar); }
519 * Get a valid name/id
522 if
($1 > 65535 ||
$1 < -32768)
523 yyerror("Resource's ID out of range (%d)", $1);
526 $$
->name.i_name
= $1;
531 $$
->name.s_name
= $1;
536 * Extra string recognition for CLASS statement in dialogs
538 nameid_s: nameid
{ $$
= $1; }
542 $$
->name.s_name
= $1;
546 /* get the value for a single resource*/
548 : accelerators
{ $$
= new_resource
(res_acc
, $1, $1->memopt
, $1->lvc.language
); }
549 | bitmap
{ $$
= new_resource
(res_bmp
, $1, $1->memopt
, $1->data
->lvc.language
); }
552 if
($1->type
== res_anicur
)
554 $$
= rsc
= new_resource
(res_anicur
, $1->u.ani
, $1->u.ani
->memopt
, $1->u.ani
->data
->lvc.language
);
556 else if
($1->type
== res_curg
)
559 $$
= rsc
= new_resource
(res_curg
, $1->u.curg
, $1->u.curg
->memopt
, $1->u.curg
->lvc.language
);
560 for
(cur
= $1->u.curg
->cursorlist
; cur
; cur
= cur
->next
)
562 rsc
->prev
= new_resource
(res_cur
, cur
, $1->u.curg
->memopt
, $1->u.curg
->lvc.language
);
563 rsc
->prev
->next
= rsc
;
565 rsc
->name
= new_name_id
();
566 rsc
->name
->type
= name_ord
;
567 rsc
->name
->name.i_name
= cur
->id
;
571 internal_error
(__FILE__
, __LINE__
, "Invalid top-level type %d in cursor resource\n", $1->type
);
574 | dialog
{ $$
= new_resource
(res_dlg
, $1, $1->memopt
, $1->lvc.language
); }
577 $$
= new_resource
(res_dlg
, $1, $1->memopt
, $1->lvc.language
);
581 | dlginit
{ $$
= new_resource
(res_dlginit
, $1, $1->memopt
, $1->data
->lvc.language
); }
582 | font
{ $$
= new_resource
(res_fnt
, $1, $1->memopt
, $1->data
->lvc.language
); }
583 | fontdir
{ $$
= new_resource
(res_fntdir
, $1, $1->memopt
, $1->data
->lvc.language
); }
586 if
($1->type
== res_aniico
)
588 $$
= rsc
= new_resource
(res_aniico
, $1->u.ani
, $1->u.ani
->memopt
, $1->u.ani
->data
->lvc.language
);
590 else if
($1->type
== res_icog
)
593 $$
= rsc
= new_resource
(res_icog
, $1->u.icog
, $1->u.icog
->memopt
, $1->u.icog
->lvc.language
);
594 for
(ico
= $1->u.icog
->iconlist
; ico
; ico
= ico
->next
)
596 rsc
->prev
= new_resource
(res_ico
, ico
, $1->u.icog
->memopt
, $1->u.icog
->lvc.language
);
597 rsc
->prev
->next
= rsc
;
599 rsc
->name
= new_name_id
();
600 rsc
->name
->type
= name_ord
;
601 rsc
->name
->name.i_name
= ico
->id
;
605 internal_error
(__FILE__
, __LINE__
, "Invalid top-level type %d in icon resource\n", $1->type
);
608 | menu
{ $$
= new_resource
(res_men
, $1, $1->memopt
, $1->lvc.language
); }
611 $$
= new_resource
(res_men
, $1, $1->memopt
, $1->lvc.language
);
615 | messagetable
{ $$
= new_resource
(res_msg
, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE
, $1->data
->lvc.language
); }
616 | html
{ $$
= new_resource
(res_html
, $1, $1->memopt
, $1->data
->lvc.language
); }
617 | rcdata
{ $$
= new_resource
(res_rdt
, $1, $1->memopt
, $1->data
->lvc.language
); }
618 | toolbar
{ $$
= new_resource
(res_toolbar
, $1, $1->memopt
, $1->lvc.language
); }
619 | userres
{ $$
= new_resource
(res_usr
, $1, $1->memopt
, $1->data
->lvc.language
); }
620 | versioninfo
{ $$
= new_resource
(res_ver
, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE
, $1->lvc.language
); }
624 filename: tIDENT
{ $$
= make_filename
($1); }
625 | tSTRING
{ $$
= make_filename
($1); }
628 /* ------------------------------ Bitmap ------------------------------ */
629 bitmap
: tBITMAP loadmemopts file_raw
{ $$
= new_bitmap
($3, $2); }
632 /* ------------------------------ Cursor ------------------------------ */
633 cursor
: tCURSOR loadmemopts file_raw
{
635 if
($3->size
> 4 && !memcmp
($3->data
, riff
, sizeof
(riff
)))
637 $$
->type
= res_anicur
;
638 $$
->u.ani
= new_ani_curico
(res_anicur
, $3, $2);
643 $$
->u.curg
= new_cursor_group
($3, $2);
648 /* ------------------------------ Icon ------------------------------ */
649 icon
: tICON loadmemopts file_raw
{
651 if
($3->size
> 4 && !memcmp
($3->data
, riff
, sizeof
(riff
)))
653 $$
->type
= res_aniico
;
654 $$
->u.ani
= new_ani_curico
(res_aniico
, $3, $2);
659 $$
->u.icog
= new_icon_group
($3, $2);
664 /* ------------------------------ Font ------------------------------ */
666 * The reading of raw_data for fonts is a Borland BRC
667 * extension. MS generates an error. However, it is
668 * most logical to support this, considering how wine
669 * enters things in CVS (ascii).
671 font
: tFONT loadmemopts file_raw
{ $$
= new_font
($3, $2); }
675 * The fontdir is a Borland BRC extension which only
676 * reads the data as 'raw_data' from the file.
677 * I don't know whether it is interpreted.
678 * The fontdir is generated if it was not present and
679 * fonts are defined in the source.
681 fontdir
: tFONTDIR loadmemopts file_raw
{ $$
= new_fontdir
($3, $2); }
684 /* ------------------------------ MessageTable ------------------------------ */
685 /* It might be interesting to implement the MS Message compiler here as well
686 * to get everything in one source. Might be a future project.
689 : tMESSAGETABLE loadmemopts file_raw
{
691 parser_warning
("MESSAGETABLE not supported in 16-bit mode\n");
692 $$
= new_messagetable
($3, $2);
696 /* ------------------------------ HTML ------------------------------ */
697 html
: tHTML loadmemopts file_raw
{ $$
= new_html
($3, $2); }
700 /* ------------------------------ RCData ------------------------------ */
701 rcdata
: tRCDATA loadmemopts file_raw
{ $$
= new_rcdata
($3, $2); }
704 /* ------------------------------ DLGINIT ------------------------------ */
705 dlginit
: tDLGINIT loadmemopts file_raw
{ $$
= new_dlginit
($3, $2); }
708 /* ------------------------------ UserType ------------------------------ */
709 userres
: usertype loadmemopts file_raw
{
710 #ifdef WORDS_BIGENDIAN
711 if
(pedantic
&& byteorder
!= WRC_BO_LITTLE
)
713 if
(pedantic
&& byteorder
== WRC_BO_BIG
)
715 parser_warning
("Byteordering is not little-endian and type cannot be interpreted\n");
716 $$
= new_user
($1, $3, $2);
723 $$
->name.i_name
= $1;
728 $$
->name.s_name
= $1;
732 /* ------------------------------ Accelerator ------------------------------ */
734 : tACCELERATORS loadmemopts opt_lvc tBEGIN events tEND
{
735 $$
= new_accelerator
();
743 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE
;
746 yyerror("Accelerator table must have at least one entry");
747 $$
->events
= get_event_head
($5);
753 if
(!$$
->lvc.language
)
754 $$
->lvc.language
= dup_language
(currentlanguage
);
758 events
: /* Empty */ { $$
=NULL
; }
759 | events tSTRING
',' expr acc_opt
{ $$
=add_string_event
($2, $4, $5, $1); }
760 | events expr
',' expr acc_opt
{ $$
=add_event
($2, $4, $5, $1); }
764 * The empty rule generates a s/r conflict because of {bi,u}nary expr
765 * on - and +. It cannot be solved in any way because it is the same as
766 * the if/then/else problem (LALR(1) problem). The conflict is moved
767 * away by forcing it to be in the expression handling below.
769 acc_opt
: /* Empty */ { $$
= 0; }
770 |
',' accs
{ $$
= $2; }
773 accs
: acc
{ $$
= $1; }
774 | accs
',' acc
{ $$
= $1 |
$3; }
777 acc
: tNOINVERT
{ $$
= WRC_AF_NOINVERT
; }
778 | tSHIFT
{ $$
= WRC_AF_SHIFT
; }
779 | tCONTROL
{ $$
= WRC_AF_CONTROL
; }
780 | tALT
{ $$
= WRC_AF_ALT
; }
781 | tASCII
{ $$
= WRC_AF_ASCII
; }
782 | tVIRTKEY
{ $$
= WRC_AF_VIRTKEY
; }
785 /* ------------------------------ Dialog ------------------------------ */
786 /* FIXME: Support EXSTYLE in the dialog line itself */
787 dialog
: tDIALOG loadmemopts expr
',' expr
',' expr
',' expr dlg_attributes
795 $10->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
800 $10->controls
= get_control_head
($12);
804 $$
->style
= new_style
(0,0);
805 $$
->style
->or_mask
= WS_POPUP
;
809 $$
->style
->or_mask |
= WS_CAPTION
;
811 $$
->style
->or_mask |
= DS_SETFONT
;
813 $$
->style
->or_mask
&= ~
($$
->style
->and_mask
);
814 $$
->style
->and_mask
= 0;
816 if
(!$$
->lvc.language
)
817 $$
->lvc.language
= dup_language
(currentlanguage
);
822 : /* Empty */ { $$
=new_dialog
(); }
823 | dlg_attributes tSTYLE style
{ $$
=dialog_style
($3,$1); }
824 | dlg_attributes tEXSTYLE style
{ $$
=dialog_exstyle
($3,$1); }
825 | dlg_attributes tCAPTION tSTRING
{ $$
=dialog_caption
($3,$1); }
826 | dlg_attributes opt_font
{ $$
=dialog_font
($2,$1); }
827 | dlg_attributes tCLASS nameid_s
{ $$
=dialog_class
($3,$1); }
828 | dlg_attributes tMENU nameid
{ $$
=dialog_menu
($3,$1); }
829 | dlg_attributes opt_language
{ $$
=dialog_language
($2,$1); }
830 | dlg_attributes opt_characts
{ $$
=dialog_characteristics
($2,$1); }
831 | dlg_attributes opt_version
{ $$
=dialog_version
($2,$1); }
834 ctrls
: /* Empty */ { $$
= NULL
; }
835 | ctrls tCONTROL gen_ctrl
{ $$
=ins_ctrl
(-1, 0, $3, $1); }
836 | ctrls tEDITTEXT ctrl_desc
{ $$
=ins_ctrl
(CT_EDIT
, 0, $3, $1); }
837 | ctrls tLISTBOX ctrl_desc
{ $$
=ins_ctrl
(CT_LISTBOX
, 0, $3, $1); }
838 | ctrls tCOMBOBOX ctrl_desc
{ $$
=ins_ctrl
(CT_COMBOBOX
, 0, $3, $1); }
839 | ctrls tSCROLLBAR ctrl_desc
{ $$
=ins_ctrl
(CT_SCROLLBAR
, 0, $3, $1); }
840 | ctrls tCHECKBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_CHECKBOX
, $3, $1); }
841 | ctrls tDEFPUSHBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_DEFPUSHBUTTON
, $3, $1); }
842 | ctrls tGROUPBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_GROUPBOX
, $3, $1);}
843 | ctrls tPUSHBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_PUSHBUTTON
, $3, $1); }
844 /* | ctrls tPUSHBOX lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
845 | ctrls tRADIOBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_RADIOBUTTON
, $3, $1); }
846 | ctrls tAUTO3STATE lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTO3STATE
, $3, $1); }
847 | ctrls tSTATE3 lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_3STATE
, $3, $1); }
848 | ctrls tAUTOCHECKBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTOCHECKBOX
, $3, $1); }
849 | ctrls tAUTORADIOBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTORADIOBUTTON
, $3, $1); }
850 | ctrls tLTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_LEFT
, $3, $1); }
851 | ctrls tCTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_CENTER
, $3, $1); }
852 | ctrls tRTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_RIGHT
, $3, $1); }
853 /* special treatment for icons, as the extent is optional */
854 | ctrls tICON nameid_s opt_comma expr
',' expr
',' expr iconinfo
{
859 $$
= ins_ctrl
(CT_STATIC
, SS_ICON
, $10, $1);
864 : nameid_s opt_comma expr
',' expr
',' expr
',' expr
',' expr optional_style_pair
{
874 $$
->style
= $12->style
;
878 $$
->exstyle
= $12->exstyle
;
879 $$
->gotexstyle
= TRUE
;
887 : expr
',' expr
',' expr
',' expr
',' expr optional_style_pair
{
896 $$
->style
= $10->style
;
900 $$
->exstyle
= $10->exstyle
;
901 $$
->gotexstyle
= TRUE
;
908 iconinfo: /* Empty */
909 { $$
= new_control
(); }
911 |
',' expr
',' expr
{
916 |
',' expr
',' expr
',' style
{
923 |
',' expr
',' expr
',' style
',' style
{
930 $$
->gotexstyle
= TRUE
;
934 gen_ctrl: nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr
',' style
{
938 $$
->ctlclass
= convert_ctlclass
($5);
946 $$
->gotexstyle
= TRUE
;
948 | nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr
{
952 $$
->ctlclass
= convert_ctlclass
($5);
963 : tFONT expr
',' tSTRING
{ $$
= new_font_id
($2, $4, 0, 0); }
966 /* ------------------------------ style flags ------------------------------ */
968 : /* Empty */ { $$
= NULL
; }
969 |
',' style
{ $$
= new_style_pair
($2, 0); }
970 |
',' style
',' style
{ $$
= new_style_pair
($2, $4); }
974 : style
'|' style
{ $$
= new_style
($1->or_mask |
$3->or_mask
, $1->and_mask |
$3->and_mask
); free
($1); free
($3);}
975 |
'(' style
')' { $$
= $2; }
976 | any_num
{ $$
= new_style
($1, 0); }
977 | tNOT any_num
{ $$
= new_style
(0, $2); }
984 $$
->name.i_name
= $1;
989 $$
->name.s_name
= $1;
993 /* ------------------------------ DialogEx ------------------------------ */
994 dialogex: tDIALOGEX loadmemopts expr
',' expr
',' expr
',' expr helpid dlgex_attribs
995 tBEGIN exctrls tEND
{
997 parser_warning
("DIALOGEX not supported in 16-bit mode\n");
1000 $11->memopt
= *($2);
1004 $11->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1011 $11->helpid
= *($10);
1012 $11->gothelpid
= TRUE
;
1015 $11->controls
= get_control_head
($13);
1018 assert
($$
->style
!= NULL
);
1021 $$
->style
->or_mask
= WS_POPUP
;
1022 $$
->gotstyle
= TRUE
;
1025 $$
->style
->or_mask |
= WS_CAPTION
;
1027 $$
->style
->or_mask |
= DS_SETFONT
;
1029 $$
->style
->or_mask
&= ~
($$
->style
->and_mask
);
1030 $$
->style
->and_mask
= 0;
1032 if
(!$$
->lvc.language
)
1033 $$
->lvc.language
= dup_language
(currentlanguage
);
1038 : /* Empty */ { $$
=new_dialog
(); $$
->is_ex
= TRUE
; }
1039 | dlgex_attribs tSTYLE style
{ $$
=dialog_style
($3,$1); }
1040 | dlgex_attribs tEXSTYLE style
{ $$
=dialog_exstyle
($3,$1); }
1041 | dlgex_attribs tCAPTION tSTRING
{ $$
=dialog_caption
($3,$1); }
1042 | dlgex_attribs opt_font
{ $$
=dialog_font
($2,$1); }
1043 | dlgex_attribs opt_exfont
{ $$
=dialog_font
($2,$1); }
1044 | dlgex_attribs tCLASS nameid_s
{ $$
=dialog_class
($3,$1); }
1045 | dlgex_attribs tMENU nameid
{ $$
=dialog_menu
($3,$1); }
1046 | dlgex_attribs opt_language
{ $$
=dialog_language
($2,$1); }
1047 | dlgex_attribs opt_characts
{ $$
=dialog_characteristics
($2,$1); }
1048 | dlgex_attribs opt_version
{ $$
=dialog_version
($2,$1); }
1051 exctrls
: /* Empty */ { $$
= NULL
; }
1052 | exctrls tCONTROL gen_exctrl
{ $$
=ins_ctrl
(-1, 0, $3, $1); }
1053 | exctrls tEDITTEXT exctrl_desc
{ $$
=ins_ctrl
(CT_EDIT
, 0, $3, $1); }
1054 | exctrls tLISTBOX exctrl_desc
{ $$
=ins_ctrl
(CT_LISTBOX
, 0, $3, $1); }
1055 | exctrls tCOMBOBOX exctrl_desc
{ $$
=ins_ctrl
(CT_COMBOBOX
, 0, $3, $1); }
1056 | exctrls tSCROLLBAR exctrl_desc
{ $$
=ins_ctrl
(CT_SCROLLBAR
, 0, $3, $1); }
1057 | exctrls tCHECKBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_CHECKBOX
, $3, $1); }
1058 | exctrls tDEFPUSHBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_DEFPUSHBUTTON
, $3, $1); }
1059 | exctrls tGROUPBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_GROUPBOX
, $3, $1);}
1060 | exctrls tPUSHBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_PUSHBUTTON
, $3, $1); }
1061 /* | exctrls tPUSHBOX lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
1062 | exctrls tRADIOBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_RADIOBUTTON
, $3, $1); }
1063 | exctrls tAUTO3STATE lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTO3STATE
, $3, $1); }
1064 | exctrls tSTATE3 lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_3STATE
, $3, $1); }
1065 | exctrls tAUTOCHECKBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTOCHECKBOX
, $3, $1); }
1066 | exctrls tAUTORADIOBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTORADIOBUTTON
, $3, $1); }
1067 | exctrls tLTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_LEFT
, $3, $1); }
1068 | exctrls tCTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_CENTER
, $3, $1); }
1069 | exctrls tRTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_RIGHT
, $3, $1); }
1070 /* special treatment for icons, as the extent is optional */
1071 | exctrls tICON nameid_s opt_comma expr
',' expr
',' expr iconinfo
{
1076 $$
= ins_ctrl
(CT_STATIC
, SS_ICON
, $10, $1);
1081 : nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
','
1082 expr
',' style helpid opt_data
{
1086 $$
->ctlclass
= convert_ctlclass
($5);
1088 $$
->gotstyle
= TRUE
;
1096 $$
->gotexstyle
= TRUE
;
1100 $$
->helpid
= *($18);
1101 $$
->gothelpid
= TRUE
;
1106 | nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr opt_data
{
1111 $$
->gotstyle
= TRUE
;
1112 $$
->ctlclass
= convert_ctlclass
($5);
1122 : nameid_s opt_comma expr
',' expr
',' expr
',' expr
',' expr optional_style_pair helpid opt_data
{
1132 $$
->style
= $12->style
;
1133 $$
->gotstyle
= TRUE
;
1137 $$
->exstyle
= $12->exstyle
;
1138 $$
->gotexstyle
= TRUE
;
1148 : expr
',' expr
',' expr
',' expr
',' expr optional_style_pair helpid opt_data
{
1157 $$
->style
= $10->style
;
1158 $$
->gotstyle
= TRUE
;
1162 $$
->exstyle
= $10->exstyle
;
1163 $$
->gotexstyle
= TRUE
;
1171 opt_data: /* Empty */ { $$
= NULL
; }
1172 | raw_data
{ $$
= $1; }
1175 helpid
: /* Empty */ { $$
= NULL
; }
1176 |
',' expr
{ $$
= new_int
($2); }
1180 : tFONT expr
',' tSTRING
',' expr
',' expr opt_expr
{ $$
= new_font_id
($2, $4, $6, $8); }
1184 * FIXME: This odd expression is here to nullify an extra token found
1185 * in some appstudio produced resources which appear to do nothing.
1187 opt_expr: /* Empty */ { $$
= NULL
; }
1188 |
',' expr
{ $$
= NULL
; }
1191 /* ------------------------------ Menu ------------------------------ */
1192 menu
: tMENU loadmemopts opt_lvc menu_body
{
1194 yyerror("Menu must contain items");
1202 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1203 $$
->items
= get_item_head
($4);
1209 if
(!$$
->lvc.language
)
1210 $$
->lvc.language
= dup_language
(currentlanguage
);
1215 : tBEGIN item_definitions tEND
{ $$
= $2; }
1219 : /* Empty */ {$$
= NULL
;}
1220 | item_definitions tMENUITEM tSTRING opt_comma expr item_options
{
1229 | item_definitions tMENUITEM tSEPARATOR
{
1235 | item_definitions tPOPUP tSTRING item_options menu_body
{
1236 $$
= new_menu_item
();
1240 $$
->popup
= get_item_head
($5);
1245 /* NOTE: item_options is right recursive because it would introduce
1246 * a shift/reduce conflict on ',' in itemex_options due to the
1247 * empty rule here. The parser is now forced to look beyond the ','
1248 * before reducing (force shift).
1249 * Right recursion here is not a problem because we cannot expect
1250 * more than 7 parserstack places to be occupied while parsing this
1251 * (who would want to specify a MF_x flag twice?).
1254 : /* Empty */ { $$
= 0; }
1255 |
',' item_options
{ $$
= $2; }
1256 | tCHECKED item_options
{ $$
= $2 | MF_CHECKED
; }
1257 | tGRAYED item_options
{ $$
= $2 | MF_GRAYED
; }
1258 | tHELP item_options
{ $$
= $2 | MF_HELP
; }
1259 | tINACTIVE item_options
{ $$
= $2 | MF_DISABLED
; }
1260 | tMENUBARBREAK item_options
{ $$
= $2 | MF_MENUBARBREAK
; }
1261 | tMENUBREAK item_options
{ $$
= $2 | MF_MENUBREAK
; }
1264 /* ------------------------------ MenuEx ------------------------------ */
1265 menuex
: tMENUEX loadmemopts opt_lvc menuex_body
{
1267 parser_warning
("MENUEX not supported in 16-bit mode\n");
1269 yyerror("MenuEx must contain items");
1278 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1279 $$
->items
= get_item_head
($4);
1285 if
(!$$
->lvc.language
)
1286 $$
->lvc.language
= dup_language
(currentlanguage
);
1291 : tBEGIN itemex_definitions tEND
{ $$
= $2; }
1295 : /* Empty */ {$$
= NULL
; }
1296 | itemex_definitions tMENUITEM tSTRING itemex_options
{
1297 $$
= new_menu_item
();
1303 $$
->type
= $4->type
;
1304 $$
->state
= $4->state
;
1305 $$
->helpid
= $4->helpid
;
1306 $$
->gotid
= $4->gotid
;
1307 $$
->gottype
= $4->gottype
;
1308 $$
->gotstate
= $4->gotstate
;
1309 $$
->gothelpid
= $4->gothelpid
;
1312 | itemex_definitions tMENUITEM tSEPARATOR
{
1313 $$
= new_menu_item
();
1318 | itemex_definitions tPOPUP tSTRING itemex_p_options menuex_body
{
1319 $$
= new_menu_item
();
1323 $$
->popup
= get_item_head
($5);
1326 $$
->type
= $4->type
;
1327 $$
->state
= $4->state
;
1328 $$
->helpid
= $4->helpid
;
1329 $$
->gotid
= $4->gotid
;
1330 $$
->gottype
= $4->gottype
;
1331 $$
->gotstate
= $4->gotstate
;
1332 $$
->gothelpid
= $4->gothelpid
;
1338 : /* Empty */ { $$
= new_itemex_opt
(0, 0, 0, 0); }
1340 $$
= new_itemex_opt
($2, 0, 0, 0);
1343 |
',' e_expr
',' e_expr item_options
{
1344 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $5, 0);
1347 $$
->gotstate
= TRUE
;
1351 |
',' e_expr
',' e_expr
',' expr
{
1352 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6, 0);
1355 $$
->gotstate
= TRUE
;
1362 : /* Empty */ { $$
= new_itemex_opt
(0, 0, 0, 0); }
1364 $$
= new_itemex_opt
($2, 0, 0, 0);
1367 |
',' e_expr
',' expr
{
1368 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4, 0, 0);
1373 |
',' e_expr
',' e_expr
',' expr
{
1374 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6, 0);
1379 $$
->gotstate
= TRUE
;
1381 |
',' e_expr
',' e_expr
',' e_expr
',' expr
{
1382 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6 ?
*($6) : 0, $8);
1388 $$
->gotstate
= TRUE
;
1389 $$
->gothelpid
= TRUE
;
1393 /* ------------------------------ StringTable ------------------------------ */
1394 /* Stringtables are parsed differently than other resources because their
1395 * layout is substantially different from other resources.
1396 * The table is parsed through a _global_ variable 'tagstt' which holds the
1397 * current stringtable descriptor (stringtable_t *) and 'sttres' that holds a
1398 * list of stringtables of different languages.
1401 : stt_head tBEGIN strings tEND
{
1404 yyerror("Stringtable must have at least one entry");
1409 /* Check if we added to a language table or created
1412 for
(stt
= sttres
; stt
; stt
= stt
->next
)
1419 /* It is a new one */
1422 sttres
->prev
= tagstt
;
1423 tagstt
->next
= sttres
;
1429 /* Else, we're done */
1431 free
(tagstt_memopt
);
1432 tagstt_memopt
= NULL
;
1438 /* This is to get the language of the currently parsed stringtable */
1439 stt_head: tSTRINGTABLE loadmemopts opt_lvc
{
1440 if
((tagstt
= find_stringtable
($3)) == NULL
)
1441 tagstt
= new_stringtable
($3);
1443 tagstt_version
= $3->version
;
1444 tagstt_characts
= $3->characts
;
1449 strings
: /* Empty */ { $$
= NULL
; }
1450 | strings expr opt_comma tSTRING
{
1452 assert
(tagstt
!= NULL
);
1453 if
($2 > 65535 ||
$2 < -32768)
1454 yyerror("Stringtable entry's ID out of range (%d)", $2);
1455 /* Search for the ID */
1456 for
(i
= 0; i
< tagstt
->nentries
; i
++)
1458 if
(tagstt
->entries
[i
].id
== $2)
1459 yyerror("Stringtable ID %d already in use", $2);
1461 /* If we get here, then we have a new unique entry */
1463 tagstt
->entries
= xrealloc
(tagstt
->entries
, sizeof
(tagstt
->entries
[0]) * tagstt
->nentries
);
1464 tagstt
->entries
[tagstt
->nentries
-1].id
= $2;
1465 tagstt
->entries
[tagstt
->nentries
-1].str
= $4;
1467 tagstt
->entries
[tagstt
->nentries
-1].memopt
= *tagstt_memopt
;
1469 tagstt
->entries
[tagstt
->nentries
-1].memopt
= WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE
;
1470 tagstt
->entries
[tagstt
->nentries
-1].version
= tagstt_version
;
1471 tagstt
->entries
[tagstt
->nentries
-1].characts
= tagstt_characts
;
1473 if
(pedantic
&& !$4->size
)
1474 parser_warning
("Zero length strings make no sense\n");
1475 if
(!win32
&& $4->size
> 254)
1476 yyerror("Stringtable entry more than 254 characters");
1477 if
(win32
&& $4->size
> 65534) /* Hmm..., does this happen? */
1478 yyerror("Stringtable entry more than 65534 characters (probably something else that went wrong)");
1483 opt_comma
/* There seem to be two ways to specify a stringtable... */
1488 /* ------------------------------ VersionInfo ------------------------------ */
1490 : tVERSIONINFO loadmemopts fix_version tBEGIN ver_blocks tEND
{
1498 $$
->memopt
= WRC_MO_MOVEABLE |
(win32 ? WRC_MO_PURE
: 0);
1499 $$
->blocks
= get_ver_block_head
($5);
1500 /* Set language; there is no version or characteristics */
1501 $$
->lvc.language
= dup_language
(currentlanguage
);
1506 : /* Empty */ { $$
= new_versioninfo
(); }
1507 | fix_version tFILEVERSION expr
',' expr
',' expr
',' expr
{
1509 yyerror("FILEVERSION already defined");
1511 $$
->filever_maj1
= $3;
1512 $$
->filever_maj2
= $5;
1513 $$
->filever_min1
= $7;
1514 $$
->filever_min2
= $9;
1517 | fix_version tPRODUCTVERSION expr
',' expr
',' expr
',' expr
{
1519 yyerror("PRODUCTVERSION already defined");
1521 $$
->prodver_maj1
= $3;
1522 $$
->prodver_maj2
= $5;
1523 $$
->prodver_min1
= $7;
1524 $$
->prodver_min2
= $9;
1527 | fix_version tFILEFLAGS expr
{
1529 yyerror("FILEFLAGS already defined");
1534 | fix_version tFILEFLAGSMASK expr
{
1536 yyerror("FILEFLAGSMASK already defined");
1538 $$
->fileflagsmask
= $3;
1541 | fix_version tFILEOS expr
{
1543 yyerror("FILEOS already defined");
1548 | fix_version tFILETYPE expr
{
1550 yyerror("FILETYPE already defined");
1555 | fix_version tFILESUBTYPE expr
{
1557 yyerror("FILESUBTYPE already defined");
1559 $$
->filesubtype
= $3;
1565 : /* Empty */ { $$
= NULL
; }
1566 | ver_blocks ver_block
{
1575 : tBLOCK tSTRING tBEGIN ver_values tEND
{
1576 $$
= new_ver_block
();
1578 $$
->values
= get_ver_value_head
($4);
1583 : /* Empty */ { $$
= NULL
; }
1584 | ver_values ver_value
{
1594 $$
= new_ver_value
();
1595 $$
->type
= val_block
;
1596 $$
->value.block
= $1;
1598 | tVALUE tSTRING
',' tSTRING
{
1599 $$
= new_ver_value
();
1604 | tVALUE tSTRING
',' ver_words
{
1605 $$
= new_ver_value
();
1606 $$
->type
= val_words
;
1608 $$
->value.words
= $4;
1613 : expr
{ $$
= new_ver_words
($1); }
1614 | ver_words
',' expr
{ $$
= add_ver_words
($1, $3); }
1617 /* ------------------------------ Toolbar ------------------------------ */
1618 toolbar: tTOOLBAR loadmemopts expr
',' expr opt_lvc tBEGIN toolbar_items tEND
{
1620 toolbar_item_t
*items
= get_tlbr_buttons_head
($8, &nitems
);
1621 $$
= new_toolbar
($3, $5, items
, nitems
);
1629 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE
;
1636 if
(!$$
->lvc.language
)
1638 $$
->lvc.language
= dup_language
(currentlanguage
);
1644 : /* Empty */ { $$
= NULL
; }
1645 | toolbar_items tBUTTON expr
{
1646 toolbar_item_t
*idrec
= new_toolbar_item
();
1648 $$
= ins_tlbr_button
($1, idrec
);
1650 | toolbar_items tSEPARATOR
{
1651 toolbar_item_t
*idrec
= new_toolbar_item
();
1653 $$
= ins_tlbr_button
($1, idrec
);
1657 /* ------------------------------ Memory options ------------------------------ */
1659 : /* Empty */ { $$
= NULL
; }
1660 | loadmemopts lamo
{
1670 | loadmemopts lama
{
1679 *$2 &= WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE
;
1685 lamo
: tPRELOAD
{ $$
= new_int
(WRC_MO_PRELOAD
);
1686 if
(win32
&& pedantic
) parser_warning
("PRELOAD is ignored in 32-bit mode\n"); }
1687 | tMOVEABLE
{ $$
= new_int
(WRC_MO_MOVEABLE
);
1688 if
(win32
&& pedantic
) parser_warning
("MOVEABLE is ignored in 32-bit mode\n"); }
1689 | tDISCARDABLE
{ $$
= new_int
(WRC_MO_DISCARDABLE
);
1690 if
(win32
&& pedantic
) parser_warning
("DISCARDABLE is ignored in 32-bit mode\n"); }
1691 | tPURE
{ $$
= new_int
(WRC_MO_PURE
);
1692 if
(win32
&& pedantic
) parser_warning
("PURE is ignored in 32-bit mode\n"); }
1695 lama
: tLOADONCALL
{ $$
= new_int
(~WRC_MO_PRELOAD
);
1696 if
(win32
&& pedantic
) parser_warning
("LOADONCALL is ignored in 32-bit mode\n"); }
1697 | tFIXED
{ $$
= new_int
(~WRC_MO_MOVEABLE
);
1698 if
(win32
&& pedantic
) parser_warning
("FIXED is ignored in 32-bit mode\n"); }
1699 | tIMPURE
{ $$
= new_int
(~WRC_MO_PURE
);
1700 if
(win32
&& pedantic
) parser_warning
("IMPURE is ignored in 32-bit mode\n"); }
1703 /* ------------------------------ Win32 options ------------------------------ */
1704 opt_lvc
: /* Empty */ { $$
= new_lvc
(); }
1705 | opt_lvc opt_language
{
1707 parser_warning
("LANGUAGE not supported in 16-bit mode\n");
1709 yyerror("Language already defined");
1713 | opt_lvc opt_characts
{
1715 parser_warning
("CHARACTERISTICS not supported in 16-bit mode\n");
1717 yyerror("Characteristics already defined");
1721 | opt_lvc opt_version
{
1723 parser_warning
("VERSION not supported in 16-bit mode\n");
1725 yyerror("Version already defined");
1732 * This here is another s/r conflict on {bi,u}nary + and -.
1733 * It is due to the look-ahead which must determine when the
1734 * rule opt_language ends. It could be solved with adding a
1735 * tNL at the end, but that seems unreasonable to do.
1736 * The conflict is now moved to the expression handling below.
1739 : tLANGUAGE expr
',' expr
{ $$
= new_language
($2, $4);
1740 if
(get_language_codepage
($2, $4) == -1)
1741 yyerror( "Language %04x is not supported", ($4<<10) + $2);
1746 : tCHARACTERISTICS expr
{ $$
= new_characts
($2); }
1750 : tVERSION expr
{ $$
= new_version
($2); }
1753 /* ------------------------------ Raw data handling ------------------------------ */
1754 raw_data: opt_lvc tBEGIN raw_elements tEND
{
1761 if
(!$3->lvc.language
)
1762 $3->lvc.language
= dup_language
(currentlanguage
);
1769 : tRAWDATA
{ $$
= $1; }
1770 | tNUMBER
{ $$
= int2raw_data
($1); }
1771 |
'-' tNUMBER
{ $$
= int2raw_data
(-($2)); }
1772 | tLNUMBER
{ $$
= long2raw_data
($1); }
1773 |
'-' tLNUMBER
{ $$
= long2raw_data
(-($2)); }
1774 | tSTRING
{ $$
= str2raw_data
($1); }
1775 | raw_elements opt_comma tRAWDATA
{ $$
= merge_raw_data
($1, $3); free
($3->data
); free
($3); }
1776 | raw_elements opt_comma tNUMBER
{ $$
= merge_raw_data_int
($1, $3); }
1777 | raw_elements opt_comma
'-' tNUMBER
{ $$
= merge_raw_data_int
($1, -($4)); }
1778 | raw_elements opt_comma tLNUMBER
{ $$
= merge_raw_data_long
($1, $3); }
1779 | raw_elements opt_comma
'-' tLNUMBER
{ $$
= merge_raw_data_long
($1, -($4)); }
1780 | raw_elements opt_comma tSTRING
{ $$
= merge_raw_data_str
($1, $3); }
1783 /* File data or raw data */
1784 file_raw: filename
{ $$
= load_file
($1,dup_language
(currentlanguage
)); }
1785 | raw_data
{ $$
= $1; }
1788 /* ------------------------------ Win32 expressions ------------------------------ */
1789 /* All win16 numbers are also handled here. This is inconsistent with MS
1790 * resource compiler, but what the heck, it's just handy to have.
1792 e_expr
: /* Empty */ { $$
= 0; }
1793 | expr
{ $$
= new_int
($1); }
1796 /* This rule moves ALL s/r conflicts on {bi,u}nary - and + to here */
1797 expr
: xpr
{ $$
= ($1); }
1800 xpr
: xpr
'+' xpr
{ $$
= ($1) + ($3); }
1801 | xpr
'-' xpr
{ $$
= ($1) - ($3); }
1802 | xpr
'|' xpr
{ $$
= ($1) |
($3); }
1803 | xpr
'&' xpr
{ $$
= ($1) & ($3); }
1804 | xpr
'*' xpr
{ $$
= ($1) * ($3); }
1805 | xpr
'/' xpr
{ $$
= ($1) / ($3); }
1806 | xpr
'^' xpr
{ $$
= ($1) ^
($3); }
1807 |
'~' xpr
{ $$
= ~
($2); }
1808 |
'-' xpr %prec pUPM
{ $$
= -($2); }
1809 |
'+' xpr %prec pUPM
{ $$
= $2; }
1810 |
'(' xpr
')' { $$
= $2; }
1811 | any_num
{ $$
= $1; }
1812 | tNOT any_num
{ $$
= ~
($2); }
1815 any_num
: tNUMBER
{ $$
= $1; }
1816 | tLNUMBER
{ $$
= $1; }
1820 /* Dialog specific functions */
1821 static dialog_t
*dialog_style
(style_t
* st
, dialog_t
*dlg
)
1823 assert
(dlg
!= NULL
);
1824 if
(dlg
->style
== NULL
)
1826 dlg
->style
= new_style
(0,0);
1831 parser_warning
("Style already defined, or-ing together\n");
1835 dlg
->style
->or_mask
= 0;
1836 dlg
->style
->and_mask
= 0;
1838 dlg
->style
->or_mask |
= st
->or_mask
;
1839 dlg
->style
->and_mask |
= st
->and_mask
;
1840 dlg
->gotstyle
= TRUE
;
1845 static dialog_t
*dialog_exstyle
(style_t
*st
, dialog_t
*dlg
)
1847 assert
(dlg
!= NULL
);
1848 if
(dlg
->exstyle
== NULL
)
1850 dlg
->exstyle
= new_style
(0,0);
1855 parser_warning
("ExStyle already defined, or-ing together\n");
1859 dlg
->exstyle
->or_mask
= 0;
1860 dlg
->exstyle
->and_mask
= 0;
1862 dlg
->exstyle
->or_mask |
= st
->or_mask
;
1863 dlg
->exstyle
->and_mask |
= st
->and_mask
;
1864 dlg
->gotexstyle
= TRUE
;
1869 static dialog_t
*dialog_caption
(string_t
*s
, dialog_t
*dlg
)
1871 assert
(dlg
!= NULL
);
1873 yyerror("Caption already defined");
1878 static dialog_t
*dialog_font
(font_id_t
*f
, dialog_t
*dlg
)
1880 assert
(dlg
!= NULL
);
1882 yyerror("Font already defined");
1887 static dialog_t
*dialog_class
(name_id_t
*n
, dialog_t
*dlg
)
1889 assert
(dlg
!= NULL
);
1891 yyerror("Class already defined");
1896 static dialog_t
*dialog_menu
(name_id_t
*m
, dialog_t
*dlg
)
1898 assert
(dlg
!= NULL
);
1900 yyerror("Menu already defined");
1905 static dialog_t
*dialog_language
(language_t
*l
, dialog_t
*dlg
)
1907 assert
(dlg
!= NULL
);
1908 if
(dlg
->lvc.language
)
1909 yyerror("Language already defined");
1910 dlg
->lvc.language
= l
;
1914 static dialog_t
*dialog_characteristics
(characts_t
*c
, dialog_t
*dlg
)
1916 assert
(dlg
!= NULL
);
1917 if
(dlg
->lvc.characts
)
1918 yyerror("Characteristics already defined");
1919 dlg
->lvc.characts
= c
;
1923 static dialog_t
*dialog_version
(version_t
*v
, dialog_t
*dlg
)
1925 assert
(dlg
!= NULL
);
1926 if
(dlg
->lvc.version
)
1927 yyerror("Version already defined");
1928 dlg
->lvc.version
= v
;
1932 /* Controls specific functions */
1933 static control_t
*ins_ctrl
(int type
, int special_style
, control_t
*ctrl
, control_t
*prev
)
1935 /* Hm... this seems to be jammed in at all time... */
1936 int defaultstyle
= WS_CHILD | WS_VISIBLE
;
1938 assert
(ctrl
!= NULL
);
1944 /* Check for duplicate identifiers */
1947 if
(ctrl
->id
!= -1 && ctrl
->id
== prev
->id
)
1948 parser_warning
("Duplicate dialog control id %d\n", ctrl
->id
);
1954 ctrl
->ctlclass
= new_name_id
();
1955 ctrl
->ctlclass
->type
= name_ord
;
1956 ctrl
->ctlclass
->name.i_name
= type
;
1962 if
(special_style
!= BS_GROUPBOX
&& special_style
!= BS_RADIOBUTTON
)
1963 defaultstyle |
= WS_TABSTOP
;
1966 defaultstyle |
= WS_TABSTOP | WS_BORDER
;
1969 defaultstyle |
= LBS_NOTIFY | WS_BORDER
;
1972 if
(!(ctrl
->style
->or_mask
& (CBS_SIMPLE | CBS_DROPDOWN | CBS_DROPDOWNLIST
)))
1973 defaultstyle |
= CBS_SIMPLE
;
1976 if
(special_style
== SS_CENTER || special_style
== SS_LEFT || special_style
== SS_RIGHT
)
1977 defaultstyle |
= WS_GROUP
;
1981 if
(!ctrl
->gotstyle
) /* Handle default style setting */
1986 defaultstyle |
= ES_LEFT
;
1989 defaultstyle |
= LBS_NOTIFY
;
1992 defaultstyle |
= CBS_SIMPLE | WS_TABSTOP
;
1995 defaultstyle |
= SBS_HORZ
;
1998 switch
(special_style
)
2001 case BS_DEFPUSHBUTTON
:
2003 /* case BS_PUSHBOX: */
2004 case BS_AUTORADIOBUTTON
:
2007 case BS_AUTOCHECKBOX
:
2008 defaultstyle |
= WS_TABSTOP
;
2011 parser_warning
("Unknown default button control-style 0x%08x\n", special_style
);
2013 case BS_RADIOBUTTON
:
2019 switch
(special_style
)
2024 defaultstyle |
= WS_GROUP
;
2026 case SS_ICON
: /* Special case */
2029 parser_warning
("Unknown default static control-style 0x%08x\n", special_style
);
2033 case
-1: /* Generic control */
2037 yyerror("Internal error (report this): Got weird control type 0x%08x", type
);
2041 /* The SS_ICON flag is always forced in for icon controls */
2042 if
(type
== CT_STATIC
&& special_style
== SS_ICON
)
2043 defaultstyle |
= SS_ICON
;
2045 if
(!ctrl
->gotstyle
)
2046 ctrl
->style
= new_style
(0,0);
2048 /* combine all styles */
2049 ctrl
->style
->or_mask
= ctrl
->style
->or_mask | defaultstyle | special_style
;
2050 ctrl
->gotstyle
= TRUE
;
2052 /* combine with NOT mask */
2055 ctrl
->style
->or_mask
&= ~
(ctrl
->style
->and_mask
);
2056 ctrl
->style
->and_mask
= 0;
2058 if
(ctrl
->gotexstyle
)
2060 ctrl
->exstyle
->or_mask
&= ~
(ctrl
->exstyle
->and_mask
);
2061 ctrl
->exstyle
->and_mask
= 0;
2066 static int get_class_idW
(const WCHAR
*cc
)
2068 static const WCHAR szBUTTON
[] = {'B','U','T','T','O','N',0};
2069 static const WCHAR szCOMBOBOX
[] = {'C','O','M','B','O','B','O','X',0};
2070 static const WCHAR szLISTBOX
[] = {'L','I','S','T','B','O','X',0};
2071 static const WCHAR szEDIT
[] = {'E','D','I','T',0};
2072 static const WCHAR szSTATIC
[] = {'S','T','A','T','I','C',0};
2073 static const WCHAR szSCROLLBAR
[] = {'S','C','R','O','L','L','B','A','R',0};
2075 if
(!strcmpiW
(szBUTTON
, cc
))
2077 if
(!strcmpiW
(szCOMBOBOX
, cc
))
2079 if
(!strcmpiW
(szLISTBOX
, cc
))
2081 if
(!strcmpiW
(szEDIT
, cc
))
2083 if
(!strcmpiW
(szSTATIC
, cc
))
2085 if
(!strcmpiW
(szSCROLLBAR
, cc
))
2086 return CT_SCROLLBAR
;
2091 static int get_class_idA
(const char *cc
)
2093 if
(!strcasecmp
("BUTTON", cc
))
2095 if
(!strcasecmp
("COMBOBOX", cc
))
2097 if
(!strcasecmp
("LISTBOX", cc
))
2099 if
(!strcasecmp
("EDIT", cc
))
2101 if
(!strcasecmp
("STATIC", cc
))
2103 if
(!strcasecmp
("SCROLLBAR", cc
))
2104 return CT_SCROLLBAR
;
2110 static name_id_t
*convert_ctlclass
(name_id_t
*cls
)
2114 if
(cls
->type
== name_ord
)
2116 assert
(cls
->type
== name_str
);
2117 if
(cls
->name.s_name
->type
== str_unicode
)
2118 iclass
= get_class_idW
(cls
->name.s_name
->str.wstr
);
2120 iclass
= get_class_idA
(cls
->name.s_name
->str.cstr
);
2123 return cls
; /* No default, return user controlclass */
2125 free
(cls
->name.s_name
->str.cstr
);
2126 free
(cls
->name.s_name
);
2127 cls
->type
= name_ord
;
2128 cls
->name.i_name
= iclass
;
2132 /* Accelerator specific functions */
2133 static event_t
*add_event
(int key
, int id
, int flags
, event_t
*prev
)
2135 event_t
*ev
= new_event
();
2137 if
((flags
& (WRC_AF_VIRTKEY | WRC_AF_ASCII
)) == (WRC_AF_VIRTKEY | WRC_AF_ASCII
))
2138 yyerror("Cannot use both ASCII and VIRTKEY");
2142 ev
->flags
= flags
& ~WRC_AF_ASCII
;
2149 static event_t
*add_string_event
(string_t
*key
, int id
, int flags
, event_t
*prev
)
2151 event_t
*ev
= new_event
();
2155 ev
->flags
= flags
& ~WRC_AF_ASCII
;
2162 /* MenuEx specific functions */
2163 static itemex_opt_t
*new_itemex_opt
(int id
, int type
, int state
, int helpid
)
2165 itemex_opt_t
*opt
= xmalloc
(sizeof
(itemex_opt_t
));
2166 memset
( opt
, 0, sizeof
(*opt
) );
2170 opt
->helpid
= helpid
;
2174 /* Raw data functions */
2175 static raw_data_t
*load_file
(string_t
*filename
, language_t
*lang
)
2181 int codepage
= get_language_codepage
(lang
->id
, lang
->sub
);
2183 /* FIXME: we may want to use utf-8 here */
2184 if
(codepage
<= 0 && filename
->type
!= str_char
)
2185 yyerror("Cannot convert filename to ASCII string");
2186 name
= convert_string
( filename
, str_char
, codepage
);
2187 if
(!(path
= wpp_find_include
(name
->str.cstr
, input_name
)))
2188 yyerror("Cannot open file %s", name
->str.cstr
);
2189 if
(!(fp
= fopen
( path
, "rb" )))
2190 yyerror("Cannot open file %s", name
->str.cstr
);
2192 rd
= new_raw_data
();
2193 fseek
(fp
, 0, SEEK_END
);
2194 rd
->size
= ftell
(fp
);
2195 fseek
(fp
, 0, SEEK_SET
);
2198 rd
->data
= xmalloc
(rd
->size
);
2199 fread
(rd
->data
, rd
->size
, 1, fp
);
2201 else rd
->data
= NULL
;
2203 rd
->lvc.language
= lang
;
2208 static raw_data_t
*int2raw_data
(int i
)
2212 if
( ( i
>= 0 && (int)((unsigned short)i
) != i
) ||
2213 ( i
< 0 && (int)((short)i
) != i
) )
2214 parser_warning
("Integer constant out of 16bit range (%d), truncated to %d\n", i
, (short)i
);
2216 rd
= new_raw_data
();
2217 rd
->size
= sizeof
(short);
2218 rd
->data
= xmalloc
(rd
->size
);
2221 #ifdef WORDS_BIGENDIAN
2225 rd
->data
[0] = HIBYTE
(i
);
2226 rd
->data
[1] = LOBYTE
(i
);
2229 #ifndef WORDS_BIGENDIAN
2233 rd
->data
[1] = HIBYTE
(i
);
2234 rd
->data
[0] = LOBYTE
(i
);
2240 static raw_data_t
*long2raw_data
(int i
)
2243 rd
= new_raw_data
();
2244 rd
->size
= sizeof
(int);
2245 rd
->data
= xmalloc
(rd
->size
);
2248 #ifdef WORDS_BIGENDIAN
2252 rd
->data
[0] = HIBYTE
(HIWORD
(i
));
2253 rd
->data
[1] = LOBYTE
(HIWORD
(i
));
2254 rd
->data
[2] = HIBYTE
(LOWORD
(i
));
2255 rd
->data
[3] = LOBYTE
(LOWORD
(i
));
2258 #ifndef WORDS_BIGENDIAN
2262 rd
->data
[3] = HIBYTE
(HIWORD
(i
));
2263 rd
->data
[2] = LOBYTE
(HIWORD
(i
));
2264 rd
->data
[1] = HIBYTE
(LOWORD
(i
));
2265 rd
->data
[0] = LOBYTE
(LOWORD
(i
));
2271 static raw_data_t
*str2raw_data
(string_t
*str
)
2274 rd
= new_raw_data
();
2275 rd
->size
= str
->size
* (str
->type
== str_char ?
1 : 2);
2276 rd
->data
= xmalloc
(rd
->size
);
2277 if
(str
->type
== str_char
)
2278 memcpy
(rd
->data
, str
->str.cstr
, rd
->size
);
2279 else if
(str
->type
== str_unicode
)
2284 #ifdef WORDS_BIGENDIAN
2288 for
(i
= 0; i
< str
->size
; i
++)
2290 rd
->data
[2*i
+ 0] = HIBYTE
((WORD
)str
->str.wstr
[i
]);
2291 rd
->data
[2*i
+ 1] = LOBYTE
((WORD
)str
->str.wstr
[i
]);
2294 #ifndef WORDS_BIGENDIAN
2298 for
(i
= 0; i
< str
->size
; i
++)
2300 rd
->data
[2*i
+ 1] = HIBYTE
((WORD
)str
->str.wstr
[i
]);
2301 rd
->data
[2*i
+ 0] = LOBYTE
((WORD
)str
->str.wstr
[i
]);
2307 internal_error
(__FILE__
, __LINE__
, "Invalid stringtype\n");
2311 static raw_data_t
*merge_raw_data
(raw_data_t
*r1
, raw_data_t
*r2
)
2313 r1
->data
= xrealloc
(r1
->data
, r1
->size
+ r2
->size
);
2314 memcpy
(r1
->data
+ r1
->size
, r2
->data
, r2
->size
);
2315 r1
->size
+= r2
->size
;
2319 static raw_data_t
*merge_raw_data_int
(raw_data_t
*r1
, int i
)
2321 raw_data_t
*t
= int2raw_data
(i
);
2322 merge_raw_data
(r1
, t
);
2328 static raw_data_t
*merge_raw_data_long
(raw_data_t
*r1
, int i
)
2330 raw_data_t
*t
= long2raw_data
(i
);
2331 merge_raw_data
(r1
, t
);
2337 static raw_data_t
*merge_raw_data_str
(raw_data_t
*r1
, string_t
*str
)
2339 raw_data_t
*t
= str2raw_data
(str
);
2340 merge_raw_data
(r1
, t
);
2346 /* Function the go back in a list to get the head */
2347 static menu_item_t
*get_item_head
(menu_item_t
*p
)
2356 static resource_t
*get_resource_head
(resource_t
*p
)
2365 static ver_block_t
*get_ver_block_head
(ver_block_t
*p
)
2374 static ver_value_t
*get_ver_value_head
(ver_value_t
*p
)
2383 static control_t
*get_control_head
(control_t
*p
)
2392 static event_t
*get_event_head
(event_t
*p
)
2401 /* Find a stringtable with given language */
2402 static stringtable_t
*find_stringtable
(lvc_t
*lvc
)
2406 assert
(lvc
!= NULL
);
2409 lvc
->language
= dup_language
(currentlanguage
);
2411 for
(stt
= sttres
; stt
; stt
= stt
->next
)
2413 if
(stt
->lvc.language
->id
== lvc
->language
->id
2414 && stt
->lvc.language
->sub
== lvc
->language
->sub
)
2416 /* Found a table with the same language */
2417 /* The version and characteristics are now handled
2418 * in the generation of the individual stringtables.
2419 * This enables localized analysis.
2420 if((stt->lvc.version && lvc->version && *(stt->lvc.version) != *(lvc->version))
2421 || (!stt->lvc.version && lvc->version)
2422 || (stt->lvc.version && !lvc->version))
2423 parser_warning("Stringtable's versions are not the same, using first definition\n");
2425 if((stt->lvc.characts && lvc->characts && *(stt->lvc.characts) != *(lvc->characts))
2426 || (!stt->lvc.characts && lvc->characts)
2427 || (stt->lvc.characts && !lvc->characts))
2428 parser_warning("Stringtable's characteristics are not the same, using first definition\n");
2436 /* qsort sorting function for string table entries */
2437 #define STE(p) ((const stt_entry_t *)(p))
2438 static int sort_stt_entry
(const void *e1
, const void *e2
)
2440 return STE
(e1
)->id
- STE
(e2
)->id
;
2444 static resource_t
*build_stt_resources
(stringtable_t
*stthead
)
2447 stringtable_t
*newstt
;
2449 resource_t
*rsclist
= NULL
;
2450 resource_t
*rsctail
= NULL
;
2455 characts_t
*characts
;
2461 /* For all languages defined */
2462 for
(stt
= stthead
; stt
; stt
= stt
->next
)
2464 assert
(stt
->nentries
> 0);
2466 /* Sort the entries */
2467 if
(stt
->nentries
> 1)
2468 qsort
(stt
->entries
, stt
->nentries
, sizeof
(stt
->entries
[0]), sort_stt_entry
);
2470 for
(i
= 0; i
< stt
->nentries
; )
2472 newstt
= new_stringtable
(&stt
->lvc
);
2473 newstt
->entries
= xmalloc
(16 * sizeof
(stt_entry_t
));
2474 memset
( newstt
->entries
, 0, 16 * sizeof
(stt_entry_t
) );
2475 newstt
->nentries
= 16;
2476 newstt
->idbase
= stt
->entries
[i
].id
& ~
0xf;
2477 for
(j
= 0; j
< 16 && i
< stt
->nentries
; j
++)
2479 if
(stt
->entries
[i
].id
- newstt
->idbase
== j
)
2481 newstt
->entries
[j
] = stt
->entries
[i
];
2489 /* Check individual memory options and get
2490 * the first characteristics/version
2492 for
(j
= 0; j
< 16; j
++)
2494 if
(!newstt
->entries
[j
].str
)
2496 andsum
&= newstt
->entries
[j
].memopt
;
2497 orsum |
= newstt
->entries
[j
].memopt
;
2499 characts
= newstt
->entries
[j
].characts
;
2501 version
= newstt
->entries
[j
].version
;
2505 warning
("Stringtable's memory options are not equal (idbase: %d)\n", newstt
->idbase
);
2507 /* Check version and characteristics */
2508 for
(j
= 0; j
< 16; j
++)
2511 && newstt
->entries
[j
].characts
2512 && *newstt
->entries
[j
].characts
!= *characts
)
2513 warning
("Stringtable's characteristics are not the same (idbase: %d)\n", newstt
->idbase
);
2515 && newstt
->entries
[j
].version
2516 && *newstt
->entries
[j
].version
!= *version
)
2517 warning
("Stringtable's versions are not the same (idbase: %d)\n", newstt
->idbase
);
2519 rsc
= new_resource
(res_stt
, newstt
, newstt
->memopt
, newstt
->lvc.language
);
2520 rsc
->name
= new_name_id
();
2521 rsc
->name
->type
= name_ord
;
2522 rsc
->name
->name.i_name
= (newstt
->idbase
>> 4) + 1;
2523 rsc
->memopt
= andsum
; /* Set to least common denominator */
2524 newstt
->memopt
= andsum
;
2525 newstt
->lvc.characts
= characts
;
2526 newstt
->lvc.version
= version
;
2534 rsctail
->next
= rsc
;
2535 rsc
->prev
= rsctail
;
2544 static toolbar_item_t
*ins_tlbr_button
(toolbar_item_t
*prev
, toolbar_item_t
*idrec
)
2553 static toolbar_item_t
*get_tlbr_buttons_head
(toolbar_item_t
*p
, int *nitems
)
2572 static string_t
*make_filename
(string_t
*str
)
2574 if
(str
->type
== str_char
)
2578 /* Remove escaped backslash and convert to forward */
2579 for
(cptr
= str
->str.cstr
; (cptr
= strchr
(cptr
, '\\')) != NULL
; cptr
++)
2583 memmove
(cptr
, cptr
+1, strlen
(cptr
));
2593 /* Remove escaped backslash and convert to forward */
2594 for
(wptr
= str
->str.wstr
; (wptr
= strchrW
(wptr
, '\\')) != NULL
; wptr
++)
2598 memmove
(wptr
, wptr
+1, strlenW
(wptr
));
2608 * Process all resources to extract fonts and build
2609 * a fontdir resource.
2611 * Note: MS' resource compiler (build 1472) does not
2612 * handle font resources with different languages.
2613 * The fontdir is generated in the last active language
2614 * and font identifiers must be unique across the entire
2616 * This is not logical considering the localization
2617 * constraints of all other resource types. MS has,
2618 * most probably, never testet localized fonts. However,
2619 * using fontresources is rare, so it might not occur
2620 * in normal applications.
2621 * Wine does require better localization because a lot
2622 * of languages are coded into the same executable.
2623 * Therefore, I will generate fontdirs for *each*
2624 * localized set of fonts.
2626 static resource_t
*build_fontdir
(resource_t
**fnt
, int nfnt
)
2628 static int once
= 0;
2631 warning
("Need to parse fonts, not yet implemented (fnt: %p, nfnt: %d)\n", fnt
, nfnt
);
2637 static resource_t
*build_fontdirs
(resource_t
*tail
)
2640 resource_t
*lst
= NULL
;
2641 resource_t
**fnt
= NULL
; /* List of all fonts */
2643 resource_t
**fnd
= NULL
; /* List of all fontdirs */
2645 resource_t
**lanfnt
= NULL
;
2652 nid.type
= name_str
;
2653 nid.name.s_name
= &str
;
2654 str.type
= str_char
;
2655 str.str.cstr
= xstrdup
("FONTDIR");
2658 /* Extract all fonts and fontdirs */
2659 for
(rsc
= tail
; rsc
; rsc
= rsc
->prev
)
2661 if
(rsc
->type
== res_fnt
)
2664 fnt
= xrealloc
(fnt
, nfnt
* sizeof
(*fnt
));
2667 else if
(rsc
->type
== res_fntdir
)
2670 fnd
= xrealloc
(fnd
, nfnd
* sizeof
(*fnd
));
2675 /* Verify the name of the present fontdirs */
2676 for
(i
= 0; i
< nfnd
; i
++)
2678 if
(compare_name_id
(&nid
, fnd
[i
]->name
))
2680 warning
("User supplied FONTDIR entry has an invalid name '%s', ignored\n",
2681 get_nameid_str
(fnd
[i
]->name
));
2690 warning
("Found %d FONTDIR entries without any fonts present\n", nfnd
);
2695 lanfnt
= xmalloc
(nfnt
* sizeof
(*lanfnt
));
2696 memset
( lanfnt
, 0, nfnt
* sizeof
(*lanfnt
));
2698 /* Get all fonts covered by fontdirs */
2699 for
(i
= 0; i
< nfnd
; i
++)
2707 for
(j
= 0; j
< nfnt
; j
++)
2711 if
(fnt
[j
]->lan
->id
== fnd
[i
]->lan
->id
&& fnt
[j
]->lan
->sub
== fnd
[i
]->lan
->sub
)
2713 lanfnt
[nlanfnt
] = fnt
[j
];
2719 cnt
= *(WORD
*)fnd
[i
]->res.fnd
->data
->data
;
2722 else if
(nlanfnt
== BYTESWAP_WORD
(cnt
))
2725 error("FONTDIR for language %d,%d has wrong count (%d, expected %d)\n",
2726 fnd
[i
]->lan
->id
, fnd
[i
]->lan
->sub
, cnt
, nlanfnt
);
2727 #ifdef WORDS_BIGENDIAN
2728 if
((byteorder
== WRC_BO_LITTLE
&& !isswapped
) ||
(byteorder
!= WRC_BO_LITTLE
&& isswapped
))
2730 if
((byteorder
== WRC_BO_BIG
&& !isswapped
) ||
(byteorder
!= WRC_BO_BIG
&& isswapped
))
2733 internal_error
(__FILE__
, __LINE__
, "User supplied FONTDIR needs byteswapping\n");
2737 /* We now have fonts left where we need to make a fontdir resource */
2738 for
(i
= fntleft
= 0; i
< nfnt
; i
++)
2745 /* Get fonts of same language in lanfnt[] */
2746 for
(i
= nlanfnt
= 0; i
< nfnt
; i
++)
2753 lanfnt
[nlanfnt
] = fnt
[i
];
2758 else if
(fnt
[i
]->lan
->id
== lanfnt
[0]->lan
->id
&& fnt
[i
]->lan
->sub
== lanfnt
[0]->lan
->sub
)
2762 /* and build a fontdir */
2763 rsc
= build_fontdir
(lanfnt
, nlanfnt
);
2784 * This gets invoked to determine whether the next resource
2785 * is to be of a standard-type (e.g. bitmaps etc.), or should
2786 * be a user-type resource. This function is required because
2787 * there is the _possibility_ of a lookahead token in the
2788 * parser, which is generated from the "expr" state in the
2791 * The general resource format is:
2792 * <identifier> <type> <flags> <resourcebody>
2794 * The <identifier> can either be tIDENT or "expr". The latter
2795 * will always generate a lookahead, which is the <type> of the
2796 * resource to parse. Otherwise, we need to get a new token from
2797 * the scanner to determine the next step.
2799 * The problem arrises when <type> is numerical. This case should
2800 * map onto default resource-types and be parsed as such instead
2801 * of being mapped onto user-type resources.
2803 * The trick lies in the fact that yacc (bison) doesn't care about
2804 * intermediate changes of the lookahead while reducing a rule. We
2805 * simply replace the lookahead with a token that will result in
2806 * a shift to the appropriate rule for the specific resource-type.
2808 static int rsrcid_to_token
(int lookahead
)
2812 /* Get a token if we don't have one yet */
2813 if
(lookahead
== YYEMPTY
)
2814 lookahead
= yylex();
2816 /* Only numbers are possibly interesting */
2842 case WRC_RT_FONTDIR
:
2848 case WRC_RT_MESSAGETABLE
:
2849 token
= tMESSAGETABLE
;
2851 case WRC_RT_DLGINIT
:
2854 case WRC_RT_ACCELERATOR
:
2855 token
= tACCELERATORS
;
2863 case WRC_RT_VERSION
:
2864 token
= tVERSIONINFO
;
2866 case WRC_RT_TOOLBAR
:
2876 case WRC_RT_ANICURSOR
:
2877 case WRC_RT_ANIICON
:
2878 case WRC_RT_GROUP_CURSOR
:
2879 case WRC_RT_GROUP_ICON
:
2880 parser_warning
("Usertype uses reserved type ID %d, which is auto-generated\n", yylval.num
);
2883 case WRC_RT_DLGINCLUDE
:
2884 case WRC_RT_PLUGPLAY
:
2886 parser_warning
("Usertype uses reserved type ID %d, which is not supported by wrc yet\n", yylval.num
);