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"
138 #include "wine/unicode.h"
146 /* Berkeley yacc (byacc) doesn't seem to know about these */
147 /* Some *BSD supplied versions do define these though */
149 # define YYEMPTY (-1) /* Empty lookahead value of yychar */
152 # define YYLEX yylex()
155 #elif defined(YYBISON)
156 /* Bison was used for original development */
157 /* #define YYEMPTY -2 */
158 /* #define YYLEX yylex() */
161 /* No yacc we know yet */
162 # if !defined(YYEMPTY) || !defined(YYLEX)
163 # error Yacc version/type unknown. This version needs to be verified for settings of YYEMPTY and YYLEX.
164 # elif defined(__GNUC__) /* gcc defines the #warning directive */
165 # warning Yacc version/type unknown. It defines YYEMPTY and YYLEX, but is not tested
166 /* #else we just take a chance that it works... */
170 int want_nl
= 0; /* Signal flex that we need the next newline */
171 int want_id
= 0; /* Signal flex that we need the next identifier */
172 static stringtable_t
*tagstt
; /* Stringtable tag.
173 * It is set while parsing a stringtable to one of
174 * the stringtables in the sttres list or a new one
175 * if the language was not parsed before.
177 static stringtable_t
*sttres
; /* Stringtable resources. This holds the list of
178 * stringtables with different lanuages
180 static int dont_want_id
= 0; /* See language parsing for details */
182 /* Set to the current options of the currently scanning stringtable */
183 static int *tagstt_memopt
;
184 static characts_t
*tagstt_characts
;
185 static version_t
*tagstt_version
;
187 static const char riff
[4] = "RIFF"; /* RIFF file magic for animated cursor/icon */
189 /* Prototypes of here defined functions */
190 static event_t
*get_event_head
(event_t
*p
);
191 static control_t
*get_control_head
(control_t
*p
);
192 static ver_value_t
*get_ver_value_head
(ver_value_t
*p
);
193 static ver_block_t
*get_ver_block_head
(ver_block_t
*p
);
194 static resource_t
*get_resource_head
(resource_t
*p
);
195 static menu_item_t
*get_item_head
(menu_item_t
*p
);
196 static raw_data_t
*merge_raw_data_str
(raw_data_t
*r1
, string_t
*str
);
197 static raw_data_t
*merge_raw_data_int
(raw_data_t
*r1
, int i
);
198 static raw_data_t
*merge_raw_data_long
(raw_data_t
*r1
, int i
);
199 static raw_data_t
*merge_raw_data
(raw_data_t
*r1
, raw_data_t
*r2
);
200 static raw_data_t
*str2raw_data
(string_t
*str
);
201 static raw_data_t
*int2raw_data
(int i
);
202 static raw_data_t
*long2raw_data
(int i
);
203 static raw_data_t
*load_file
(string_t
*name
, language_t
*lang
);
204 static itemex_opt_t
*new_itemex_opt
(int id
, int type
, int state
, int helpid
);
205 static event_t
*add_string_event
(string_t
*key
, int id
, int flags
, event_t
*prev
);
206 static event_t
*add_event
(int key
, int id
, int flags
, event_t
*prev
);
207 static name_id_t
*convert_ctlclass
(name_id_t
*cls
);
208 static control_t
*ins_ctrl
(int type
, int special_style
, control_t
*ctrl
, control_t
*prev
);
209 static dialog_t
*dialog_version
(version_t
*v
, dialog_t
*dlg
);
210 static dialog_t
*dialog_characteristics
(characts_t
*c
, dialog_t
*dlg
);
211 static dialog_t
*dialog_language
(language_t
*l
, dialog_t
*dlg
);
212 static dialog_t
*dialog_menu
(name_id_t
*m
, dialog_t
*dlg
);
213 static dialog_t
*dialog_class
(name_id_t
*n
, dialog_t
*dlg
);
214 static dialog_t
*dialog_font
(font_id_t
*f
, dialog_t
*dlg
);
215 static dialog_t
*dialog_caption
(string_t
*s
, dialog_t
*dlg
);
216 static dialog_t
*dialog_exstyle
(style_t
* st
, dialog_t
*dlg
);
217 static dialog_t
*dialog_style
(style_t
* st
, dialog_t
*dlg
);
218 static resource_t
*build_stt_resources
(stringtable_t
*stthead
);
219 static stringtable_t
*find_stringtable
(lvc_t
*lvc
);
220 static toolbar_item_t
*ins_tlbr_button
(toolbar_item_t
*prev
, toolbar_item_t
*idrec
);
221 static toolbar_item_t
*get_tlbr_buttons_head
(toolbar_item_t
*p
, int *nitems
);
222 static string_t
*make_filename
(string_t
*s
);
223 static resource_t
*build_fontdirs
(resource_t
*tail
);
224 static resource_t
*build_fontdir
(resource_t
**fnt
, int nfnt
);
225 static int rsrcid_to_token
(int lookahead
);
262 toolbar_item_t
*tlbarItems
;
264 style_pair_t
*styles
;
270 %token
<num
> tNUMBER tLNUMBER
271 %token
<str
> tSTRING tIDENT tFILENAME
272 %token
<raw
> tRAWDATA
273 %token tACCELERATORS tBITMAP tCURSOR tDIALOG tDIALOGEX tMENU tMENUEX tMESSAGETABLE
274 %token tRCDATA tVERSIONINFO tSTRINGTABLE tFONT tFONTDIR tICON tHTML
275 %token tAUTO3STATE tAUTOCHECKBOX tAUTORADIOBUTTON tCHECKBOX tDEFPUSHBUTTON
276 %token tPUSHBUTTON tRADIOBUTTON tSTATE3
/* PUSHBOX */
277 %token tGROUPBOX tCOMBOBOX tLISTBOX tSCROLLBAR
278 %token tCONTROL tEDITTEXT
279 %token tRTEXT tCTEXT tLTEXT
281 %token tSHIFT tALT tASCII tVIRTKEY tGRAYED tCHECKED tINACTIVE tNOINVERT
282 %token tPURE tIMPURE tDISCARDABLE tLOADONCALL tPRELOAD tFIXED tMOVEABLE
283 %token tCLASS tCAPTION tCHARACTERISTICS tEXSTYLE tSTYLE tVERSION tLANGUAGE
284 %token tFILEVERSION tPRODUCTVERSION tFILEFLAGSMASK tFILEOS tFILETYPE tFILEFLAGS tFILESUBTYPE
285 %token tMENUBARBREAK tMENUBREAK tMENUITEM tPOPUP tSEPARATOR
287 %token tTOOLBAR tBUTTON
298 %type
<res
> resource_file resource resources resource_definition
299 %type
<stt
> stringtable strings
302 %type
<acc
> accelerators
305 %type
<ani
> cursor icon
306 %type
<dlg
> dialog dlg_attributes dialogex dlgex_attribs
307 %type
<ctl
> ctrls gen_ctrl lab_ctrl ctrl_desc iconinfo
309 %type
<ctl
> exctrls gen_exctrl lab_exctrl exctrl_desc
312 %type
<raw
> raw_data raw_elements opt_data file_raw
313 %type
<veri
> versioninfo fix_version
314 %type
<verw
> ver_words
315 %type
<blk
> ver_blocks ver_block
316 %type
<val
> ver_values ver_value
317 %type
<men
> menu menuex
318 %type
<menitm
> item_definitions menu_body itemex_definitions menuex_body
319 %type
<exopt
> itemex_p_options itemex_options
320 %type
<msg
> messagetable
322 %type
<num
> item_options
323 %type
<nid
> nameid nameid_s ctlclass usertype
324 %type
<num
> acc_opt acc accs
325 %type
<iptr
> loadmemopts lamo lama
326 %type
<fntid
> opt_font opt_exfont opt_expr
328 %type
<lan
> opt_language
329 %type
<chars
> opt_characts
330 %type
<ver
> opt_version
333 %type
<tlbar
> toolbar
334 %type
<tlbarItems
> toolbar_items
335 %type
<dginit
> dlginit
336 %type
<styles
> optional_style_pair
345 resource_t
*rsc
, *head
;
346 /* First add stringtables to the resource-list */
347 rsc
= build_stt_resources
(sttres
);
348 /* 'build_stt_resources' returns a head and $1 is a tail */
357 /* Find the tail again */
358 while
($1 && $1->next
)
360 /* Now add any fontdirecory */
361 rsc
= build_fontdirs
($1);
362 /* 'build_fontdir' returns a head and $1 is a tail */
372 /* Final statements before we're done */
373 if
((head
= get_resource_head
($1)) != NULL
)
375 if
(resource_top
) /* append to existing resources */
377 resource_t
*tail
= resource_top
;
378 while
(tail
->next
) tail
= tail
->next
;
382 else resource_top
= head
;
388 /* Resources are put into a linked list */
390 : /* Empty */ { $$
= NULL
; want_id
= 1; }
391 | resources resource
{
394 resource_t
*tail
= $2;
395 resource_t
*head
= $2;
404 /* Check for duplicate identifiers */
407 resource_t
*rsc
= $1;
410 if
(rsc
->type
== head
->type
411 && rsc
->lan
->id
== head
->lan
->id
412 && rsc
->lan
->sub
== head
->lan
->sub
413 && !compare_name_id
(rsc
->name
, head
->name
)
414 && (rsc
->type
!= res_usr ||
!compare_name_id
(rsc
->res.usr
->type
,head
->res.usr
->type
)))
416 yyerror("Duplicate resource name '%s'", get_nameid_str
(rsc
->name
));
425 resource_t
*tail
= $1;
433 if
(!dont_want_id
) /* See comments in language parsing below */
438 * The following newline rule will never get reduced because we never
439 * get the tNL token, unless we explicitly set the 'want_nl'
440 * flag, which we don't.
441 * The *ONLY* reason for this to be here is because Berkeley
442 * yacc (byacc), at least version 1.9, has a bug.
443 * (identified in the generated parser on the second
445 * static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93";
447 * This extra rule fixes it.
448 * The problem is that the expression handling rule "expr: xpr"
449 * is not reduced on non-terminal tokens, defined above in the
450 * %token declarations. Token tNL is the only non-terminal that
451 * can occur. The error becomes visible in the language parsing
452 * rule below, which looks at the look-ahead token and tests it
453 * for tNL. However, byacc already generates an error upon reading
454 * the token instead of keeping it as a lookahead. The reason
455 * lies in the lack of a $default transition in the "expr : xpr . "
456 * state (currently state 25). It is probably omitted because tNL
457 * is a non-terminal and the state contains 2 s/r conflicts. The
458 * state enumerates all possible transitions instead of using a
459 * $default transition.
460 * All in all, it is a bug in byacc. (period)
466 /* Parse top level resource definitions etc. */
468 : expr usrcvt resource_definition
{
472 if
($1 > 65535 ||
$1 < -32768)
473 yyerror("Resource's ID out of range (%d)", $1);
474 $$
->name
= new_name_id
();
475 $$
->name
->type
= name_ord
;
476 $$
->name
->name.i_name
= $1;
477 chat
("Got %s (%d)\n", get_typename
($3), $$
->name
->name.i_name
);
480 | tIDENT usrcvt resource_definition
{
484 $$
->name
= new_name_id
();
485 $$
->name
->type
= name_str
;
486 $$
->name
->name.s_name
= $1;
487 chat
("Got %s (%s)\n", get_typename
($3), $$
->name
->name.s_name
->str.cstr
);
491 /* Don't do anything, stringtables are converted to
492 * resource_t structures when we are finished parsing and
493 * the final rule of the parser is reduced (see above)
496 chat
("Got STRINGTABLE\n");
498 | tLANGUAGE
{want_nl
= 1; } expr
',' expr
{
499 /* We *NEED* the newline to delimit the expression.
500 * Otherwise, we would not be able to set the next
501 * want_id anymore because of the token-lookahead.
503 * However, we can test the lookahead-token for
504 * being "non-expression" type, in which case we
505 * continue. Fortunately, tNL is the only token that
506 * will break expression parsing and is implicitly
507 * void, so we just remove it. This scheme makes it
508 * possible to do some (not all) fancy preprocessor
510 * BTW, we also need to make sure that the next
511 * reduction of 'resources' above will *not* set
512 * want_id because we already have a lookahead that
515 if
(yychar != YYEMPTY
&& yychar != tNL
)
519 yychar = YYEMPTY
; /* Could use 'yyclearin', but we already need the*/
520 /* direct access to yychar in rule 'usrcvt' below. */
521 else if
(yychar == tIDENT
)
522 parser_warning
("LANGUAGE statement not delimited with newline; next identifier might be wrong\n");
524 want_nl
= 0; /* We don't want it anymore if we didn't get it */
527 parser_warning
("LANGUAGE not supported in 16-bit mode\n");
528 free
(currentlanguage
);
529 if
(get_language_codepage
($3, $5) == -1)
530 yyerror( "Language %04x is not supported", ($5<<10) + $3);
531 currentlanguage
= new_language
($3, $5);
533 chat
("Got LANGUAGE %d,%d (0x%04x)\n", $3, $5, ($5<<10) + $3);
538 * Remapping of numerical resource types
539 * (see also comment of called function below)
541 usrcvt
: /* Empty */ { yychar = rsrcid_to_token
(yychar); }
545 * Get a valid name/id
548 if
($1 > 65535 ||
$1 < -32768)
549 yyerror("Resource's ID out of range (%d)", $1);
552 $$
->name.i_name
= $1;
557 $$
->name.s_name
= $1;
562 * Extra string recognition for CLASS statement in dialogs
564 nameid_s: nameid
{ $$
= $1; }
568 $$
->name.s_name
= $1;
572 /* get the value for a single resource*/
574 : accelerators
{ $$
= new_resource
(res_acc
, $1, $1->memopt
, $1->lvc.language
); }
575 | bitmap
{ $$
= new_resource
(res_bmp
, $1, $1->memopt
, $1->data
->lvc.language
); }
578 if
($1->type
== res_anicur
)
580 $$
= rsc
= new_resource
(res_anicur
, $1->u.ani
, $1->u.ani
->memopt
, $1->u.ani
->data
->lvc.language
);
582 else if
($1->type
== res_curg
)
585 $$
= rsc
= new_resource
(res_curg
, $1->u.curg
, $1->u.curg
->memopt
, $1->u.curg
->lvc.language
);
586 for
(cur
= $1->u.curg
->cursorlist
; cur
; cur
= cur
->next
)
588 rsc
->prev
= new_resource
(res_cur
, cur
, $1->u.curg
->memopt
, $1->u.curg
->lvc.language
);
589 rsc
->prev
->next
= rsc
;
591 rsc
->name
= new_name_id
();
592 rsc
->name
->type
= name_ord
;
593 rsc
->name
->name.i_name
= cur
->id
;
597 internal_error
(__FILE__
, __LINE__
, "Invalid top-level type %d in cursor resource\n", $1->type
);
600 | dialog
{ $$
= new_resource
(res_dlg
, $1, $1->memopt
, $1->lvc.language
); }
603 $$
= new_resource
(res_dlg
, $1, $1->memopt
, $1->lvc.language
);
607 | dlginit
{ $$
= new_resource
(res_dlginit
, $1, $1->memopt
, $1->data
->lvc.language
); }
608 | font
{ $$
= new_resource
(res_fnt
, $1, $1->memopt
, $1->data
->lvc.language
); }
609 | fontdir
{ $$
= new_resource
(res_fntdir
, $1, $1->memopt
, $1->data
->lvc.language
); }
612 if
($1->type
== res_aniico
)
614 $$
= rsc
= new_resource
(res_aniico
, $1->u.ani
, $1->u.ani
->memopt
, $1->u.ani
->data
->lvc.language
);
616 else if
($1->type
== res_icog
)
619 $$
= rsc
= new_resource
(res_icog
, $1->u.icog
, $1->u.icog
->memopt
, $1->u.icog
->lvc.language
);
620 for
(ico
= $1->u.icog
->iconlist
; ico
; ico
= ico
->next
)
622 rsc
->prev
= new_resource
(res_ico
, ico
, $1->u.icog
->memopt
, $1->u.icog
->lvc.language
);
623 rsc
->prev
->next
= rsc
;
625 rsc
->name
= new_name_id
();
626 rsc
->name
->type
= name_ord
;
627 rsc
->name
->name.i_name
= ico
->id
;
631 internal_error
(__FILE__
, __LINE__
, "Invalid top-level type %d in icon resource\n", $1->type
);
634 | menu
{ $$
= new_resource
(res_men
, $1, $1->memopt
, $1->lvc.language
); }
637 $$
= new_resource
(res_men
, $1, $1->memopt
, $1->lvc.language
);
641 | messagetable
{ $$
= new_resource
(res_msg
, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE
, $1->data
->lvc.language
); }
642 | html
{ $$
= new_resource
(res_html
, $1, $1->memopt
, $1->data
->lvc.language
); }
643 | rcdata
{ $$
= new_resource
(res_rdt
, $1, $1->memopt
, $1->data
->lvc.language
); }
644 | toolbar
{ $$
= new_resource
(res_toolbar
, $1, $1->memopt
, $1->lvc.language
); }
645 | userres
{ $$
= new_resource
(res_usr
, $1, $1->memopt
, $1->data
->lvc.language
); }
646 | versioninfo
{ $$
= new_resource
(res_ver
, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE
, $1->lvc.language
); }
650 filename: tFILENAME
{ $$
= make_filename
($1); }
651 | tIDENT
{ $$
= make_filename
($1); }
652 | tSTRING
{ $$
= make_filename
($1); }
655 /* ------------------------------ Bitmap ------------------------------ */
656 bitmap
: tBITMAP loadmemopts file_raw
{ $$
= new_bitmap
($3, $2); }
659 /* ------------------------------ Cursor ------------------------------ */
660 cursor
: tCURSOR loadmemopts file_raw
{
662 if
($3->size
> 4 && !memcmp
($3->data
, riff
, sizeof
(riff
)))
664 $$
->type
= res_anicur
;
665 $$
->u.ani
= new_ani_curico
(res_anicur
, $3, $2);
670 $$
->u.curg
= new_cursor_group
($3, $2);
675 /* ------------------------------ Icon ------------------------------ */
676 icon
: tICON loadmemopts file_raw
{
678 if
($3->size
> 4 && !memcmp
($3->data
, riff
, sizeof
(riff
)))
680 $$
->type
= res_aniico
;
681 $$
->u.ani
= new_ani_curico
(res_aniico
, $3, $2);
686 $$
->u.icog
= new_icon_group
($3, $2);
691 /* ------------------------------ Font ------------------------------ */
693 * The reading of raw_data for fonts is a Borland BRC
694 * extension. MS generates an error. However, it is
695 * most logical to support this, considering how wine
696 * enters things in CVS (ascii).
698 font
: tFONT loadmemopts file_raw
{ $$
= new_font
($3, $2); }
702 * The fontdir is a Borland BRC extension which only
703 * reads the data as 'raw_data' from the file.
704 * I don't know whether it is interpreted.
705 * The fontdir is generated if it was not present and
706 * fonts are defined in the source.
708 fontdir
: tFONTDIR loadmemopts file_raw
{ $$
= new_fontdir
($3, $2); }
711 /* ------------------------------ MessageTable ------------------------------ */
712 /* It might be interesting to implement the MS Message compiler here as well
713 * to get everything in one source. Might be a future project.
716 : tMESSAGETABLE loadmemopts file_raw
{
718 parser_warning
("MESSAGETABLE not supported in 16-bit mode\n");
719 $$
= new_messagetable
($3, $2);
723 /* ------------------------------ HTML ------------------------------ */
724 html
: tHTML loadmemopts file_raw
{ $$
= new_html
($3, $2); }
727 /* ------------------------------ RCData ------------------------------ */
728 rcdata
: tRCDATA loadmemopts file_raw
{ $$
= new_rcdata
($3, $2); }
731 /* ------------------------------ DLGINIT ------------------------------ */
732 dlginit
: tDLGINIT loadmemopts file_raw
{ $$
= new_dlginit
($3, $2); }
735 /* ------------------------------ UserType ------------------------------ */
736 userres
: usertype loadmemopts file_raw
{
737 #ifdef WORDS_BIGENDIAN
738 if
(pedantic
&& byteorder
!= WRC_BO_LITTLE
)
740 if
(pedantic
&& byteorder
== WRC_BO_BIG
)
742 parser_warning
("Byteordering is not little-endian and type cannot be interpreted\n");
743 $$
= new_user
($1, $3, $2);
750 $$
->name.i_name
= $1;
755 $$
->name.s_name
= $1;
759 /* ------------------------------ Accelerator ------------------------------ */
761 : tACCELERATORS loadmemopts opt_lvc tBEGIN events tEND
{
762 $$
= new_accelerator
();
770 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE
;
773 yyerror("Accelerator table must have at least one entry");
774 $$
->events
= get_event_head
($5);
780 if
(!$$
->lvc.language
)
781 $$
->lvc.language
= dup_language
(currentlanguage
);
785 events
: /* Empty */ { $$
=NULL
; }
786 | events tSTRING
',' expr acc_opt
{ $$
=add_string_event
($2, $4, $5, $1); }
787 | events expr
',' expr acc_opt
{ $$
=add_event
($2, $4, $5, $1); }
791 * The empty rule generates a s/r conflict because of {bi,u}nary expr
792 * on - and +. It cannot be solved in any way because it is the same as
793 * the if/then/else problem (LALR(1) problem). The conflict is moved
794 * away by forcing it to be in the expression handling below.
796 acc_opt
: /* Empty */ { $$
= 0; }
797 |
',' accs
{ $$
= $2; }
800 accs
: acc
{ $$
= $1; }
801 | accs
',' acc
{ $$
= $1 |
$3; }
804 acc
: tNOINVERT
{ $$
= WRC_AF_NOINVERT
; }
805 | tSHIFT
{ $$
= WRC_AF_SHIFT
; }
806 | tCONTROL
{ $$
= WRC_AF_CONTROL
; }
807 | tALT
{ $$
= WRC_AF_ALT
; }
808 | tASCII
{ $$
= WRC_AF_ASCII
; }
809 | tVIRTKEY
{ $$
= WRC_AF_VIRTKEY
; }
812 /* ------------------------------ Dialog ------------------------------ */
813 /* FIXME: Support EXSTYLE in the dialog line itself */
814 dialog
: tDIALOG loadmemopts expr
',' expr
',' expr
',' expr dlg_attributes
822 $10->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
827 $10->controls
= get_control_head
($12);
831 $$
->style
= new_style
(0,0);
832 $$
->style
->or_mask
= WS_POPUP
;
836 $$
->style
->or_mask |
= WS_CAPTION
;
838 $$
->style
->or_mask |
= DS_SETFONT
;
840 $$
->style
->or_mask
&= ~
($$
->style
->and_mask
);
841 $$
->style
->and_mask
= 0;
843 if
(!$$
->lvc.language
)
844 $$
->lvc.language
= dup_language
(currentlanguage
);
849 : /* Empty */ { $$
=new_dialog
(); }
850 | dlg_attributes tSTYLE style
{ $$
=dialog_style
($3,$1); }
851 | dlg_attributes tEXSTYLE style
{ $$
=dialog_exstyle
($3,$1); }
852 | dlg_attributes tCAPTION tSTRING
{ $$
=dialog_caption
($3,$1); }
853 | dlg_attributes opt_font
{ $$
=dialog_font
($2,$1); }
854 | dlg_attributes tCLASS nameid_s
{ $$
=dialog_class
($3,$1); }
855 | dlg_attributes tMENU nameid
{ $$
=dialog_menu
($3,$1); }
856 | dlg_attributes opt_language
{ $$
=dialog_language
($2,$1); }
857 | dlg_attributes opt_characts
{ $$
=dialog_characteristics
($2,$1); }
858 | dlg_attributes opt_version
{ $$
=dialog_version
($2,$1); }
861 ctrls
: /* Empty */ { $$
= NULL
; }
862 | ctrls tCONTROL gen_ctrl
{ $$
=ins_ctrl
(-1, 0, $3, $1); }
863 | ctrls tEDITTEXT ctrl_desc
{ $$
=ins_ctrl
(CT_EDIT
, 0, $3, $1); }
864 | ctrls tLISTBOX ctrl_desc
{ $$
=ins_ctrl
(CT_LISTBOX
, 0, $3, $1); }
865 | ctrls tCOMBOBOX ctrl_desc
{ $$
=ins_ctrl
(CT_COMBOBOX
, 0, $3, $1); }
866 | ctrls tSCROLLBAR ctrl_desc
{ $$
=ins_ctrl
(CT_SCROLLBAR
, 0, $3, $1); }
867 | ctrls tCHECKBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_CHECKBOX
, $3, $1); }
868 | ctrls tDEFPUSHBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_DEFPUSHBUTTON
, $3, $1); }
869 | ctrls tGROUPBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_GROUPBOX
, $3, $1);}
870 | ctrls tPUSHBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_PUSHBUTTON
, $3, $1); }
871 /* | ctrls tPUSHBOX lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
872 | ctrls tRADIOBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_RADIOBUTTON
, $3, $1); }
873 | ctrls tAUTO3STATE lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTO3STATE
, $3, $1); }
874 | ctrls tSTATE3 lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_3STATE
, $3, $1); }
875 | ctrls tAUTOCHECKBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTOCHECKBOX
, $3, $1); }
876 | ctrls tAUTORADIOBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTORADIOBUTTON
, $3, $1); }
877 | ctrls tLTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_LEFT
, $3, $1); }
878 | ctrls tCTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_CENTER
, $3, $1); }
879 | ctrls tRTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_RIGHT
, $3, $1); }
880 /* special treatment for icons, as the extent is optional */
881 | ctrls tICON nameid_s opt_comma expr
',' expr
',' expr iconinfo
{
886 $$
= ins_ctrl
(CT_STATIC
, SS_ICON
, $10, $1);
891 : nameid_s opt_comma expr
',' expr
',' expr
',' expr
',' expr optional_style_pair
{
901 $$
->style
= $12->style
;
905 $$
->exstyle
= $12->exstyle
;
906 $$
->gotexstyle
= TRUE
;
914 : expr
',' expr
',' expr
',' expr
',' expr optional_style_pair
{
923 $$
->style
= $10->style
;
927 $$
->exstyle
= $10->exstyle
;
928 $$
->gotexstyle
= TRUE
;
935 iconinfo: /* Empty */
936 { $$
= new_control
(); }
938 |
',' expr
',' expr
{
943 |
',' expr
',' expr
',' style
{
950 |
',' expr
',' expr
',' style
',' style
{
957 $$
->gotexstyle
= TRUE
;
961 gen_ctrl: nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr
',' style
{
965 $$
->ctlclass
= convert_ctlclass
($5);
973 $$
->gotexstyle
= TRUE
;
975 | nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr
{
979 $$
->ctlclass
= convert_ctlclass
($5);
990 : tFONT expr
',' tSTRING
{ $$
= new_font_id
($2, $4, 0, 0); }
993 /* ------------------------------ style flags ------------------------------ */
995 : /* Empty */ { $$
= NULL
; }
996 |
',' style
{ $$
= new_style_pair
($2, 0); }
997 |
',' style
',' style
{ $$
= new_style_pair
($2, $4); }
1001 : style
'|' style
{ $$
= new_style
($1->or_mask |
$3->or_mask
, $1->and_mask |
$3->and_mask
); free
($1); free
($3);}
1002 |
'(' style
')' { $$
= $2; }
1003 | any_num
{ $$
= new_style
($1, 0); }
1004 | tNOT any_num
{ $$
= new_style
(0, $2); }
1010 $$
->type
= name_ord
;
1011 $$
->name.i_name
= $1;
1015 $$
->type
= name_str
;
1016 $$
->name.s_name
= $1;
1020 /* ------------------------------ DialogEx ------------------------------ */
1021 dialogex: tDIALOGEX loadmemopts expr
',' expr
',' expr
',' expr helpid dlgex_attribs
1022 tBEGIN exctrls tEND
{
1024 parser_warning
("DIALOGEX not supported in 16-bit mode\n");
1027 $11->memopt
= *($2);
1031 $11->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1038 $11->helpid
= *($10);
1039 $11->gothelpid
= TRUE
;
1042 $11->controls
= get_control_head
($13);
1045 assert
($$
->style
!= NULL
);
1048 $$
->style
->or_mask
= WS_POPUP
;
1049 $$
->gotstyle
= TRUE
;
1052 $$
->style
->or_mask |
= WS_CAPTION
;
1054 $$
->style
->or_mask |
= DS_SETFONT
;
1056 $$
->style
->or_mask
&= ~
($$
->style
->and_mask
);
1057 $$
->style
->and_mask
= 0;
1059 if
(!$$
->lvc.language
)
1060 $$
->lvc.language
= dup_language
(currentlanguage
);
1065 : /* Empty */ { $$
=new_dialog
(); $$
->is_ex
= TRUE
; }
1066 | dlgex_attribs tSTYLE style
{ $$
=dialog_style
($3,$1); }
1067 | dlgex_attribs tEXSTYLE style
{ $$
=dialog_exstyle
($3,$1); }
1068 | dlgex_attribs tCAPTION tSTRING
{ $$
=dialog_caption
($3,$1); }
1069 | dlgex_attribs opt_font
{ $$
=dialog_font
($2,$1); }
1070 | dlgex_attribs opt_exfont
{ $$
=dialog_font
($2,$1); }
1071 | dlgex_attribs tCLASS nameid_s
{ $$
=dialog_class
($3,$1); }
1072 | dlgex_attribs tMENU nameid
{ $$
=dialog_menu
($3,$1); }
1073 | dlgex_attribs opt_language
{ $$
=dialog_language
($2,$1); }
1074 | dlgex_attribs opt_characts
{ $$
=dialog_characteristics
($2,$1); }
1075 | dlgex_attribs opt_version
{ $$
=dialog_version
($2,$1); }
1078 exctrls
: /* Empty */ { $$
= NULL
; }
1079 | exctrls tCONTROL gen_exctrl
{ $$
=ins_ctrl
(-1, 0, $3, $1); }
1080 | exctrls tEDITTEXT exctrl_desc
{ $$
=ins_ctrl
(CT_EDIT
, 0, $3, $1); }
1081 | exctrls tLISTBOX exctrl_desc
{ $$
=ins_ctrl
(CT_LISTBOX
, 0, $3, $1); }
1082 | exctrls tCOMBOBOX exctrl_desc
{ $$
=ins_ctrl
(CT_COMBOBOX
, 0, $3, $1); }
1083 | exctrls tSCROLLBAR exctrl_desc
{ $$
=ins_ctrl
(CT_SCROLLBAR
, 0, $3, $1); }
1084 | exctrls tCHECKBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_CHECKBOX
, $3, $1); }
1085 | exctrls tDEFPUSHBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_DEFPUSHBUTTON
, $3, $1); }
1086 | exctrls tGROUPBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_GROUPBOX
, $3, $1);}
1087 | exctrls tPUSHBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_PUSHBUTTON
, $3, $1); }
1088 /* | exctrls tPUSHBOX lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
1089 | exctrls tRADIOBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_RADIOBUTTON
, $3, $1); }
1090 | exctrls tAUTO3STATE lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTO3STATE
, $3, $1); }
1091 | exctrls tSTATE3 lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_3STATE
, $3, $1); }
1092 | exctrls tAUTOCHECKBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTOCHECKBOX
, $3, $1); }
1093 | exctrls tAUTORADIOBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTORADIOBUTTON
, $3, $1); }
1094 | exctrls tLTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_LEFT
, $3, $1); }
1095 | exctrls tCTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_CENTER
, $3, $1); }
1096 | exctrls tRTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_RIGHT
, $3, $1); }
1097 /* special treatment for icons, as the extent is optional */
1098 | exctrls tICON nameid_s opt_comma expr
',' expr
',' expr iconinfo
{
1103 $$
= ins_ctrl
(CT_STATIC
, SS_ICON
, $10, $1);
1108 : nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
','
1109 expr
',' style helpid opt_data
{
1113 $$
->ctlclass
= convert_ctlclass
($5);
1115 $$
->gotstyle
= TRUE
;
1123 $$
->gotexstyle
= TRUE
;
1127 $$
->helpid
= *($18);
1128 $$
->gothelpid
= TRUE
;
1133 | nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr opt_data
{
1138 $$
->gotstyle
= TRUE
;
1139 $$
->ctlclass
= convert_ctlclass
($5);
1149 : nameid_s opt_comma expr
',' expr
',' expr
',' expr
',' expr optional_style_pair helpid opt_data
{
1159 $$
->style
= $12->style
;
1160 $$
->gotstyle
= TRUE
;
1164 $$
->exstyle
= $12->exstyle
;
1165 $$
->gotexstyle
= TRUE
;
1175 : expr
',' expr
',' expr
',' expr
',' expr optional_style_pair helpid opt_data
{
1184 $$
->style
= $10->style
;
1185 $$
->gotstyle
= TRUE
;
1189 $$
->exstyle
= $10->exstyle
;
1190 $$
->gotexstyle
= TRUE
;
1198 opt_data: /* Empty */ { $$
= NULL
; }
1199 | raw_data
{ $$
= $1; }
1202 helpid
: /* Empty */ { $$
= NULL
; }
1203 |
',' expr
{ $$
= new_int
($2); }
1207 : tFONT expr
',' tSTRING
',' expr
',' expr opt_expr
{ $$
= new_font_id
($2, $4, $6, $8); }
1211 * FIXME: This odd expression is here to nullify an extra token found
1212 * in some appstudio produced resources which appear to do nothing.
1214 opt_expr: /* Empty */ { $$
= NULL
; }
1215 |
',' expr
{ $$
= NULL
; }
1218 /* ------------------------------ Menu ------------------------------ */
1219 menu
: tMENU loadmemopts opt_lvc menu_body
{
1221 yyerror("Menu must contain items");
1229 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1230 $$
->items
= get_item_head
($4);
1236 if
(!$$
->lvc.language
)
1237 $$
->lvc.language
= dup_language
(currentlanguage
);
1242 : tBEGIN item_definitions tEND
{ $$
= $2; }
1246 : /* Empty */ {$$
= NULL
;}
1247 | item_definitions tMENUITEM tSTRING opt_comma expr item_options
{
1256 | item_definitions tMENUITEM tSEPARATOR
{
1262 | item_definitions tPOPUP tSTRING item_options menu_body
{
1263 $$
= new_menu_item
();
1267 $$
->popup
= get_item_head
($5);
1272 /* NOTE: item_options is right recursive because it would introduce
1273 * a shift/reduce conflict on ',' in itemex_options due to the
1274 * empty rule here. The parser is now forced to look beyond the ','
1275 * before reducing (force shift).
1276 * Right recursion here is not a problem because we cannot expect
1277 * more than 7 parserstack places to be occupied while parsing this
1278 * (who would want to specify a MF_x flag twice?).
1281 : /* Empty */ { $$
= 0; }
1282 |
',' item_options
{ $$
= $2; }
1283 | tCHECKED item_options
{ $$
= $2 | MF_CHECKED
; }
1284 | tGRAYED item_options
{ $$
= $2 | MF_GRAYED
; }
1285 | tHELP item_options
{ $$
= $2 | MF_HELP
; }
1286 | tINACTIVE item_options
{ $$
= $2 | MF_DISABLED
; }
1287 | tMENUBARBREAK item_options
{ $$
= $2 | MF_MENUBARBREAK
; }
1288 | tMENUBREAK item_options
{ $$
= $2 | MF_MENUBREAK
; }
1291 /* ------------------------------ MenuEx ------------------------------ */
1292 menuex
: tMENUEX loadmemopts opt_lvc menuex_body
{
1294 parser_warning
("MENUEX not supported in 16-bit mode\n");
1296 yyerror("MenuEx must contain items");
1305 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1306 $$
->items
= get_item_head
($4);
1312 if
(!$$
->lvc.language
)
1313 $$
->lvc.language
= dup_language
(currentlanguage
);
1318 : tBEGIN itemex_definitions tEND
{ $$
= $2; }
1322 : /* Empty */ {$$
= NULL
; }
1323 | itemex_definitions tMENUITEM tSTRING itemex_options
{
1324 $$
= new_menu_item
();
1330 $$
->type
= $4->type
;
1331 $$
->state
= $4->state
;
1332 $$
->helpid
= $4->helpid
;
1333 $$
->gotid
= $4->gotid
;
1334 $$
->gottype
= $4->gottype
;
1335 $$
->gotstate
= $4->gotstate
;
1336 $$
->gothelpid
= $4->gothelpid
;
1339 | itemex_definitions tMENUITEM tSEPARATOR
{
1340 $$
= new_menu_item
();
1345 | itemex_definitions tPOPUP tSTRING itemex_p_options menuex_body
{
1346 $$
= new_menu_item
();
1350 $$
->popup
= get_item_head
($5);
1353 $$
->type
= $4->type
;
1354 $$
->state
= $4->state
;
1355 $$
->helpid
= $4->helpid
;
1356 $$
->gotid
= $4->gotid
;
1357 $$
->gottype
= $4->gottype
;
1358 $$
->gotstate
= $4->gotstate
;
1359 $$
->gothelpid
= $4->gothelpid
;
1365 : /* Empty */ { $$
= new_itemex_opt
(0, 0, 0, 0); }
1367 $$
= new_itemex_opt
($2, 0, 0, 0);
1370 |
',' e_expr
',' e_expr item_options
{
1371 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $5, 0);
1374 $$
->gotstate
= TRUE
;
1378 |
',' e_expr
',' e_expr
',' expr
{
1379 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6, 0);
1382 $$
->gotstate
= TRUE
;
1389 : /* Empty */ { $$
= new_itemex_opt
(0, 0, 0, 0); }
1391 $$
= new_itemex_opt
($2, 0, 0, 0);
1394 |
',' e_expr
',' expr
{
1395 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4, 0, 0);
1400 |
',' e_expr
',' e_expr
',' expr
{
1401 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6, 0);
1406 $$
->gotstate
= TRUE
;
1408 |
',' e_expr
',' e_expr
',' e_expr
',' expr
{
1409 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6 ?
*($6) : 0, $8);
1415 $$
->gotstate
= TRUE
;
1416 $$
->gothelpid
= TRUE
;
1420 /* ------------------------------ StringTable ------------------------------ */
1421 /* Stringtables are parsed differently than other resources because their
1422 * layout is substantially different from other resources.
1423 * The table is parsed through a _global_ variable 'tagstt' which holds the
1424 * current stringtable descriptor (stringtable_t *) and 'sttres' that holds a
1425 * list of stringtables of different languages.
1428 : stt_head tBEGIN strings tEND
{
1431 yyerror("Stringtable must have at least one entry");
1436 /* Check if we added to a language table or created
1439 for
(stt
= sttres
; stt
; stt
= stt
->next
)
1446 /* It is a new one */
1449 sttres
->prev
= tagstt
;
1450 tagstt
->next
= sttres
;
1456 /* Else were done */
1458 free
(tagstt_memopt
);
1459 tagstt_memopt
= NULL
;
1465 /* This is to get the language of the currently parsed stringtable */
1466 stt_head: tSTRINGTABLE loadmemopts opt_lvc
{
1467 if
((tagstt
= find_stringtable
($3)) == NULL
)
1468 tagstt
= new_stringtable
($3);
1470 tagstt_version
= $3->version
;
1471 tagstt_characts
= $3->characts
;
1476 strings
: /* Empty */ { $$
= NULL
; }
1477 | strings expr opt_comma tSTRING
{
1479 assert
(tagstt
!= NULL
);
1480 if
($2 > 65535 ||
$2 < -32768)
1481 yyerror("Stringtable entry's ID out of range (%d)", $2);
1482 /* Search for the ID */
1483 for
(i
= 0; i
< tagstt
->nentries
; i
++)
1485 if
(tagstt
->entries
[i
].id
== $2)
1486 yyerror("Stringtable ID %d already in use", $2);
1488 /* If we get here, then we have a new unique entry */
1490 tagstt
->entries
= xrealloc
(tagstt
->entries
, sizeof
(tagstt
->entries
[0]) * tagstt
->nentries
);
1491 tagstt
->entries
[tagstt
->nentries
-1].id
= $2;
1492 tagstt
->entries
[tagstt
->nentries
-1].str
= $4;
1494 tagstt
->entries
[tagstt
->nentries
-1].memopt
= *tagstt_memopt
;
1496 tagstt
->entries
[tagstt
->nentries
-1].memopt
= WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE
;
1497 tagstt
->entries
[tagstt
->nentries
-1].version
= tagstt_version
;
1498 tagstt
->entries
[tagstt
->nentries
-1].characts
= tagstt_characts
;
1500 if
(pedantic
&& !$4->size
)
1501 parser_warning
("Zero length strings make no sense\n");
1502 if
(!win32
&& $4->size
> 254)
1503 yyerror("Stringtable entry more than 254 characters");
1504 if
(win32
&& $4->size
> 65534) /* Hmm..., does this happen? */
1505 yyerror("Stringtable entry more than 65534 characters (probably something else that went wrong)");
1510 opt_comma
/* There seem to be two ways to specify a stringtable... */
1515 /* ------------------------------ VersionInfo ------------------------------ */
1517 : tVERSIONINFO loadmemopts fix_version tBEGIN ver_blocks tEND
{
1525 $$
->memopt
= WRC_MO_MOVEABLE |
(win32 ? WRC_MO_PURE
: 0);
1526 $$
->blocks
= get_ver_block_head
($5);
1527 /* Set language; there is no version or characteristics */
1528 $$
->lvc.language
= dup_language
(currentlanguage
);
1533 : /* Empty */ { $$
= new_versioninfo
(); }
1534 | fix_version tFILEVERSION expr
',' expr
',' expr
',' expr
{
1536 yyerror("FILEVERSION already defined");
1538 $$
->filever_maj1
= $3;
1539 $$
->filever_maj2
= $5;
1540 $$
->filever_min1
= $7;
1541 $$
->filever_min2
= $9;
1544 | fix_version tPRODUCTVERSION expr
',' expr
',' expr
',' expr
{
1546 yyerror("PRODUCTVERSION already defined");
1548 $$
->prodver_maj1
= $3;
1549 $$
->prodver_maj2
= $5;
1550 $$
->prodver_min1
= $7;
1551 $$
->prodver_min2
= $9;
1554 | fix_version tFILEFLAGS expr
{
1556 yyerror("FILEFLAGS already defined");
1561 | fix_version tFILEFLAGSMASK expr
{
1563 yyerror("FILEFLAGSMASK already defined");
1565 $$
->fileflagsmask
= $3;
1568 | fix_version tFILEOS expr
{
1570 yyerror("FILEOS already defined");
1575 | fix_version tFILETYPE expr
{
1577 yyerror("FILETYPE already defined");
1582 | fix_version tFILESUBTYPE expr
{
1584 yyerror("FILESUBTYPE already defined");
1586 $$
->filesubtype
= $3;
1592 : /* Empty */ { $$
= NULL
; }
1593 | ver_blocks ver_block
{
1602 : tBLOCK tSTRING tBEGIN ver_values tEND
{
1603 $$
= new_ver_block
();
1605 $$
->values
= get_ver_value_head
($4);
1610 : /* Empty */ { $$
= NULL
; }
1611 | ver_values ver_value
{
1621 $$
= new_ver_value
();
1622 $$
->type
= val_block
;
1623 $$
->value.block
= $1;
1625 | tVALUE tSTRING
',' tSTRING
{
1626 $$
= new_ver_value
();
1631 | tVALUE tSTRING
',' ver_words
{
1632 $$
= new_ver_value
();
1633 $$
->type
= val_words
;
1635 $$
->value.words
= $4;
1640 : expr
{ $$
= new_ver_words
($1); }
1641 | ver_words
',' expr
{ $$
= add_ver_words
($1, $3); }
1644 /* ------------------------------ Toolbar ------------------------------ */
1645 toolbar: tTOOLBAR loadmemopts expr
',' expr opt_lvc tBEGIN toolbar_items tEND
{
1647 toolbar_item_t
*items
= get_tlbr_buttons_head
($8, &nitems
);
1648 $$
= new_toolbar
($3, $5, items
, nitems
);
1656 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE
;
1663 if
(!$$
->lvc.language
)
1665 $$
->lvc.language
= dup_language
(currentlanguage
);
1671 : /* Empty */ { $$
= NULL
; }
1672 | toolbar_items tBUTTON expr
{
1673 toolbar_item_t
*idrec
= new_toolbar_item
();
1675 $$
= ins_tlbr_button
($1, idrec
);
1677 | toolbar_items tSEPARATOR
{
1678 toolbar_item_t
*idrec
= new_toolbar_item
();
1680 $$
= ins_tlbr_button
($1, idrec
);
1684 /* ------------------------------ Memory options ------------------------------ */
1686 : /* Empty */ { $$
= NULL
; }
1687 | loadmemopts lamo
{
1697 | loadmemopts lama
{
1706 *$2 &= WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE
;
1712 lamo
: tPRELOAD
{ $$
= new_int
(WRC_MO_PRELOAD
);
1713 if
(win32
&& pedantic
) parser_warning
("PRELOAD is ignored in 32-bit mode\n"); }
1714 | tMOVEABLE
{ $$
= new_int
(WRC_MO_MOVEABLE
);
1715 if
(win32
&& pedantic
) parser_warning
("MOVEABLE is ignored in 32-bit mode\n"); }
1716 | tDISCARDABLE
{ $$
= new_int
(WRC_MO_DISCARDABLE
);
1717 if
(win32
&& pedantic
) parser_warning
("DISCARDABLE is ignored in 32-bit mode\n"); }
1718 | tPURE
{ $$
= new_int
(WRC_MO_PURE
);
1719 if
(win32
&& pedantic
) parser_warning
("PURE is ignored in 32-bit mode\n"); }
1722 lama
: tLOADONCALL
{ $$
= new_int
(~WRC_MO_PRELOAD
);
1723 if
(win32
&& pedantic
) parser_warning
("LOADONCALL is ignored in 32-bit mode\n"); }
1724 | tFIXED
{ $$
= new_int
(~WRC_MO_MOVEABLE
);
1725 if
(win32
&& pedantic
) parser_warning
("FIXED is ignored in 32-bit mode\n"); }
1726 | tIMPURE
{ $$
= new_int
(~WRC_MO_PURE
);
1727 if
(win32
&& pedantic
) parser_warning
("IMPURE is ignored in 32-bit mode\n"); }
1730 /* ------------------------------ Win32 options ------------------------------ */
1731 opt_lvc
: /* Empty */ { $$
= new_lvc
(); }
1732 | opt_lvc opt_language
{
1734 parser_warning
("LANGUAGE not supported in 16-bit mode\n");
1736 yyerror("Language already defined");
1740 | opt_lvc opt_characts
{
1742 parser_warning
("CHARACTERISTICS not supported in 16-bit mode\n");
1744 yyerror("Characteristics already defined");
1748 | opt_lvc opt_version
{
1750 parser_warning
("VERSION not supported in 16-bit mode\n");
1752 yyerror("Version already defined");
1759 * This here is another s/r conflict on {bi,u}nary + and -.
1760 * It is due to the look-ahead which must determine when the
1761 * rule opt_language ends. It could be solved with adding a
1762 * tNL at the end, but that seems unreasonable to do.
1763 * The conflict is now moved to the expression handling below.
1766 : tLANGUAGE expr
',' expr
{ $$
= new_language
($2, $4);
1767 if
(get_language_codepage
($2, $4) == -1)
1768 yyerror( "Language %04x is not supported", ($4<<10) + $2);
1773 : tCHARACTERISTICS expr
{ $$
= new_characts
($2); }
1777 : tVERSION expr
{ $$
= new_version
($2); }
1780 /* ------------------------------ Raw data handling ------------------------------ */
1781 raw_data: opt_lvc tBEGIN raw_elements tEND
{
1788 if
(!$3->lvc.language
)
1789 $3->lvc.language
= dup_language
(currentlanguage
);
1796 : tRAWDATA
{ $$
= $1; }
1797 | tNUMBER
{ $$
= int2raw_data
($1); }
1798 |
'-' tNUMBER
{ $$
= int2raw_data
(-($2)); }
1799 | tLNUMBER
{ $$
= long2raw_data
($1); }
1800 |
'-' tLNUMBER
{ $$
= long2raw_data
(-($2)); }
1801 | tSTRING
{ $$
= str2raw_data
($1); }
1802 | raw_elements opt_comma tRAWDATA
{ $$
= merge_raw_data
($1, $3); free
($3->data
); free
($3); }
1803 | raw_elements opt_comma tNUMBER
{ $$
= merge_raw_data_int
($1, $3); }
1804 | raw_elements opt_comma
'-' tNUMBER
{ $$
= merge_raw_data_int
($1, -($4)); }
1805 | raw_elements opt_comma tLNUMBER
{ $$
= merge_raw_data_long
($1, $3); }
1806 | raw_elements opt_comma
'-' tLNUMBER
{ $$
= merge_raw_data_long
($1, -($4)); }
1807 | raw_elements opt_comma tSTRING
{ $$
= merge_raw_data_str
($1, $3); }
1810 /* File data or raw data */
1811 file_raw: filename
{ $$
= load_file
($1,dup_language
(currentlanguage
)); }
1812 | raw_data
{ $$
= $1; }
1815 /* ------------------------------ Win32 expressions ------------------------------ */
1816 /* All win16 numbers are also handled here. This is inconsistent with MS'
1817 * resource compiler, but what the heck, its just handy to have.
1819 e_expr
: /* Empty */ { $$
= 0; }
1820 | expr
{ $$
= new_int
($1); }
1823 /* This rule moves ALL s/r conflicts on {bi,u}nary - and + to here */
1824 expr
: xpr
{ $$
= ($1); }
1827 xpr
: xpr
'+' xpr
{ $$
= ($1) + ($3); }
1828 | xpr
'-' xpr
{ $$
= ($1) - ($3); }
1829 | xpr
'|' xpr
{ $$
= ($1) |
($3); }
1830 | xpr
'&' xpr
{ $$
= ($1) & ($3); }
1831 | xpr
'*' xpr
{ $$
= ($1) * ($3); }
1832 | xpr
'/' xpr
{ $$
= ($1) / ($3); }
1833 | xpr
'^' xpr
{ $$
= ($1) ^
($3); }
1834 |
'~' xpr
{ $$
= ~
($2); }
1835 |
'-' xpr %prec pUPM
{ $$
= -($2); }
1836 |
'+' xpr %prec pUPM
{ $$
= $2; }
1837 |
'(' xpr
')' { $$
= $2; }
1838 | any_num
{ $$
= $1; }
1839 | tNOT any_num
{ $$
= ~
($2); }
1842 any_num
: tNUMBER
{ $$
= $1; }
1843 | tLNUMBER
{ $$
= $1; }
1847 /* Dialog specific functions */
1848 static dialog_t
*dialog_style
(style_t
* st
, dialog_t
*dlg
)
1850 assert
(dlg
!= NULL
);
1851 if
(dlg
->style
== NULL
)
1853 dlg
->style
= new_style
(0,0);
1858 parser_warning
("Style already defined, or-ing together\n");
1862 dlg
->style
->or_mask
= 0;
1863 dlg
->style
->and_mask
= 0;
1865 dlg
->style
->or_mask |
= st
->or_mask
;
1866 dlg
->style
->and_mask |
= st
->and_mask
;
1867 dlg
->gotstyle
= TRUE
;
1872 static dialog_t
*dialog_exstyle
(style_t
*st
, dialog_t
*dlg
)
1874 assert
(dlg
!= NULL
);
1875 if
(dlg
->exstyle
== NULL
)
1877 dlg
->exstyle
= new_style
(0,0);
1882 parser_warning
("ExStyle already defined, or-ing together\n");
1886 dlg
->exstyle
->or_mask
= 0;
1887 dlg
->exstyle
->and_mask
= 0;
1889 dlg
->exstyle
->or_mask |
= st
->or_mask
;
1890 dlg
->exstyle
->and_mask |
= st
->and_mask
;
1891 dlg
->gotexstyle
= TRUE
;
1896 static dialog_t
*dialog_caption
(string_t
*s
, dialog_t
*dlg
)
1898 assert
(dlg
!= NULL
);
1900 yyerror("Caption already defined");
1905 static dialog_t
*dialog_font
(font_id_t
*f
, dialog_t
*dlg
)
1907 assert
(dlg
!= NULL
);
1909 yyerror("Font already defined");
1914 static dialog_t
*dialog_class
(name_id_t
*n
, dialog_t
*dlg
)
1916 assert
(dlg
!= NULL
);
1918 yyerror("Class already defined");
1923 static dialog_t
*dialog_menu
(name_id_t
*m
, dialog_t
*dlg
)
1925 assert
(dlg
!= NULL
);
1927 yyerror("Menu already defined");
1932 static dialog_t
*dialog_language
(language_t
*l
, dialog_t
*dlg
)
1934 assert
(dlg
!= NULL
);
1935 if
(dlg
->lvc.language
)
1936 yyerror("Language already defined");
1937 dlg
->lvc.language
= l
;
1941 static dialog_t
*dialog_characteristics
(characts_t
*c
, dialog_t
*dlg
)
1943 assert
(dlg
!= NULL
);
1944 if
(dlg
->lvc.characts
)
1945 yyerror("Characteristics already defined");
1946 dlg
->lvc.characts
= c
;
1950 static dialog_t
*dialog_version
(version_t
*v
, dialog_t
*dlg
)
1952 assert
(dlg
!= NULL
);
1953 if
(dlg
->lvc.version
)
1954 yyerror("Version already defined");
1955 dlg
->lvc.version
= v
;
1959 /* Controls specific functions */
1960 static control_t
*ins_ctrl
(int type
, int special_style
, control_t
*ctrl
, control_t
*prev
)
1962 /* Hm... this seems to be jammed in at all time... */
1963 int defaultstyle
= WS_CHILD | WS_VISIBLE
;
1965 assert
(ctrl
!= NULL
);
1971 /* Check for duplicate identifiers */
1974 if
(ctrl
->id
!= -1 && ctrl
->id
== prev
->id
)
1975 parser_warning
("Duplicate dialog control id %d\n", ctrl
->id
);
1981 ctrl
->ctlclass
= new_name_id
();
1982 ctrl
->ctlclass
->type
= name_ord
;
1983 ctrl
->ctlclass
->name.i_name
= type
;
1989 if
(special_style
!= BS_GROUPBOX
&& special_style
!= BS_RADIOBUTTON
)
1990 defaultstyle |
= WS_TABSTOP
;
1993 defaultstyle |
= WS_TABSTOP | WS_BORDER
;
1996 defaultstyle |
= LBS_NOTIFY | WS_BORDER
;
1999 if
(!(ctrl
->style
->or_mask
& (CBS_SIMPLE | CBS_DROPDOWN | CBS_DROPDOWNLIST
)))
2000 defaultstyle |
= CBS_SIMPLE
;
2003 if
(special_style
== SS_CENTER || special_style
== SS_LEFT || special_style
== SS_RIGHT
)
2004 defaultstyle |
= WS_GROUP
;
2008 if
(!ctrl
->gotstyle
) /* Handle default style setting */
2013 defaultstyle |
= ES_LEFT
;
2016 defaultstyle |
= LBS_NOTIFY
;
2019 defaultstyle |
= CBS_SIMPLE | WS_TABSTOP
;
2022 defaultstyle |
= SBS_HORZ
;
2025 switch
(special_style
)
2028 case BS_DEFPUSHBUTTON
:
2030 /* case BS_PUSHBOX: */
2031 case BS_AUTORADIOBUTTON
:
2034 case BS_AUTOCHECKBOX
:
2035 defaultstyle |
= WS_TABSTOP
;
2038 parser_warning
("Unknown default button control-style 0x%08x\n", special_style
);
2040 case BS_RADIOBUTTON
:
2046 switch
(special_style
)
2051 defaultstyle |
= WS_GROUP
;
2053 case SS_ICON
: /* Special case */
2056 parser_warning
("Unknown default static control-style 0x%08x\n", special_style
);
2060 case
-1: /* Generic control */
2064 yyerror("Internal error (report this): Got weird control type 0x%08x", type
);
2068 /* The SS_ICON flag is always forced in for icon controls */
2069 if
(type
== CT_STATIC
&& special_style
== SS_ICON
)
2070 defaultstyle |
= SS_ICON
;
2072 if
(!ctrl
->gotstyle
)
2073 ctrl
->style
= new_style
(0,0);
2075 /* combine all styles */
2076 ctrl
->style
->or_mask
= ctrl
->style
->or_mask | defaultstyle | special_style
;
2077 ctrl
->gotstyle
= TRUE
;
2079 /* combine with NOT mask */
2082 ctrl
->style
->or_mask
&= ~
(ctrl
->style
->and_mask
);
2083 ctrl
->style
->and_mask
= 0;
2085 if
(ctrl
->gotexstyle
)
2087 ctrl
->exstyle
->or_mask
&= ~
(ctrl
->exstyle
->and_mask
);
2088 ctrl
->exstyle
->and_mask
= 0;
2093 static int get_class_idW
(const WCHAR
*cc
)
2095 static const WCHAR szBUTTON
[] = {'B','U','T','T','O','N',0};
2096 static const WCHAR szCOMBOBOX
[] = {'C','O','M','B','O','B','O','X',0};
2097 static const WCHAR szLISTBOX
[] = {'L','I','S','T','B','O','X',0};
2098 static const WCHAR szEDIT
[] = {'E','D','I','T',0};
2099 static const WCHAR szSTATIC
[] = {'S','T','A','T','I','C',0};
2100 static const WCHAR szSCROLLBAR
[] = {'S','C','R','O','L','L','B','A','R',0};
2102 if
(!strcmpiW
(szBUTTON
, cc
))
2104 if
(!strcmpiW
(szCOMBOBOX
, cc
))
2106 if
(!strcmpiW
(szLISTBOX
, cc
))
2108 if
(!strcmpiW
(szEDIT
, cc
))
2110 if
(!strcmpiW
(szSTATIC
, cc
))
2112 if
(!strcmpiW
(szSCROLLBAR
, cc
))
2113 return CT_SCROLLBAR
;
2118 static int get_class_idA
(const char *cc
)
2120 if
(!strcasecmp
("BUTTON", cc
))
2122 if
(!strcasecmp
("COMBOBOX", cc
))
2124 if
(!strcasecmp
("LISTBOX", cc
))
2126 if
(!strcasecmp
("EDIT", cc
))
2128 if
(!strcasecmp
("STATIC", cc
))
2130 if
(!strcasecmp
("SCROLLBAR", cc
))
2131 return CT_SCROLLBAR
;
2137 static name_id_t
*convert_ctlclass
(name_id_t
*cls
)
2141 if
(cls
->type
== name_ord
)
2143 assert
(cls
->type
== name_str
);
2144 if
(cls
->name.s_name
->type
== str_unicode
)
2145 iclass
= get_class_idW
(cls
->name.s_name
->str.wstr
);
2147 iclass
= get_class_idA
(cls
->name.s_name
->str.cstr
);
2150 return cls
; /* No default, return user controlclass */
2152 free
(cls
->name.s_name
->str.cstr
);
2153 free
(cls
->name.s_name
);
2154 cls
->type
= name_ord
;
2155 cls
->name.i_name
= iclass
;
2159 /* Accelerator specific functions */
2160 static event_t
*add_event
(int key
, int id
, int flags
, event_t
*prev
)
2162 event_t
*ev
= new_event
();
2164 if
((flags
& (WRC_AF_VIRTKEY | WRC_AF_ASCII
)) == (WRC_AF_VIRTKEY | WRC_AF_ASCII
))
2165 yyerror("Cannot use both ASCII and VIRTKEY");
2169 ev
->flags
= flags
& ~WRC_AF_ASCII
;
2176 static event_t
*add_string_event
(string_t
*key
, int id
, int flags
, event_t
*prev
)
2179 event_t
*ev
= new_event
();
2181 if
(key
->type
== str_char
)
2183 if
((flags
& WRC_AF_VIRTKEY
) &&
2184 !((key
->str.cstr
[0] >= 'A' && key
->str.cstr
[0] <= 'Z') ||
2185 (key
->str.cstr
[0] >= '0' && key
->str.cstr
[0] <= '9')))
2186 yyerror("VIRTKEY code is not equal to ascii value");
2188 if
(key
->str.cstr
[0] == '^' && (flags
& WRC_AF_CONTROL
) != 0)
2190 yyerror("Cannot use both '^' and CONTROL modifier");
2192 else if
(key
->str.cstr
[0] == '^')
2194 keycode
= toupper
((unsigned char)key
->str.cstr
[1]) - '@';
2196 yyerror("Control-code out of range");
2199 keycode
= key
->str.cstr
[0];
2203 if
((flags
& WRC_AF_VIRTKEY
) &&
2204 !((key
->str.wstr
[0] >= 'A' && key
->str.wstr
[0] <= 'Z') ||
2205 (key
->str.wstr
[0] >= '0' && key
->str.wstr
[0] <= '9')))
2206 yyerror("VIRTKEY code is not equal to ascii value");
2208 if
(key
->str.wstr
[0] == '^' && (flags
& WRC_AF_CONTROL
) != 0)
2210 yyerror("Cannot use both '^' and CONTROL modifier");
2212 else if
(key
->str.wstr
[0] == '^')
2214 keycode
= toupperW
(key
->str.wstr
[1]) - '@';
2216 yyerror("Control-code out of range");
2219 keycode
= key
->str.wstr
[0];
2224 ev
->flags
= flags
& ~WRC_AF_ASCII
;
2231 /* MenuEx specific functions */
2232 static itemex_opt_t
*new_itemex_opt
(int id
, int type
, int state
, int helpid
)
2234 itemex_opt_t
*opt
= xmalloc
(sizeof
(itemex_opt_t
));
2235 memset
( opt
, 0, sizeof
(*opt
) );
2239 opt
->helpid
= helpid
;
2243 /* Raw data functions */
2244 static raw_data_t
*load_file
(string_t
*filename
, language_t
*lang
)
2250 int codepage
= get_language_codepage
(lang
->id
, lang
->sub
);
2252 /* FIXME: we may want to use utf-8 here */
2253 if
(codepage
<= 0 && filename
->type
!= str_char
)
2254 yyerror("Cannot convert filename to ASCII string");
2255 name
= convert_string
( filename
, str_char
, codepage
);
2256 if
(!(path
= wpp_find_include
(name
->str.cstr
, input_name
)))
2257 yyerror("Cannot open file %s", name
->str.cstr
);
2258 if
(!(fp
= fopen
( path
, "rb" )))
2259 yyerror("Cannot open file %s", name
->str.cstr
);
2261 rd
= new_raw_data
();
2262 fseek
(fp
, 0, SEEK_END
);
2263 rd
->size
= ftell
(fp
);
2264 fseek
(fp
, 0, SEEK_SET
);
2267 rd
->data
= xmalloc
(rd
->size
);
2268 fread
(rd
->data
, rd
->size
, 1, fp
);
2270 else rd
->data
= NULL
;
2272 rd
->lvc.language
= lang
;
2277 static raw_data_t
*int2raw_data
(int i
)
2281 if
( ( i
>= 0 && (int)((unsigned short)i
) != i
) ||
2282 ( i
< 0 && (int)((short)i
) != i
) )
2283 parser_warning
("Integer constant out of 16bit range (%d), truncated to %d\n", i
, (short)i
);
2285 rd
= new_raw_data
();
2286 rd
->size
= sizeof
(short);
2287 rd
->data
= xmalloc
(rd
->size
);
2290 #ifdef WORDS_BIGENDIAN
2294 rd
->data
[0] = HIBYTE
(i
);
2295 rd
->data
[1] = LOBYTE
(i
);
2298 #ifndef WORDS_BIGENDIAN
2302 rd
->data
[1] = HIBYTE
(i
);
2303 rd
->data
[0] = LOBYTE
(i
);
2309 static raw_data_t
*long2raw_data
(int i
)
2312 rd
= new_raw_data
();
2313 rd
->size
= sizeof
(int);
2314 rd
->data
= xmalloc
(rd
->size
);
2317 #ifdef WORDS_BIGENDIAN
2321 rd
->data
[0] = HIBYTE
(HIWORD
(i
));
2322 rd
->data
[1] = LOBYTE
(HIWORD
(i
));
2323 rd
->data
[2] = HIBYTE
(LOWORD
(i
));
2324 rd
->data
[3] = LOBYTE
(LOWORD
(i
));
2327 #ifndef WORDS_BIGENDIAN
2331 rd
->data
[3] = HIBYTE
(HIWORD
(i
));
2332 rd
->data
[2] = LOBYTE
(HIWORD
(i
));
2333 rd
->data
[1] = HIBYTE
(LOWORD
(i
));
2334 rd
->data
[0] = LOBYTE
(LOWORD
(i
));
2340 static raw_data_t
*str2raw_data
(string_t
*str
)
2343 rd
= new_raw_data
();
2344 rd
->size
= str
->size
* (str
->type
== str_char ?
1 : 2);
2345 rd
->data
= xmalloc
(rd
->size
);
2346 if
(str
->type
== str_char
)
2347 memcpy
(rd
->data
, str
->str.cstr
, rd
->size
);
2348 else if
(str
->type
== str_unicode
)
2353 #ifdef WORDS_BIGENDIAN
2357 for
(i
= 0; i
< str
->size
; i
++)
2359 rd
->data
[2*i
+ 0] = HIBYTE
((WORD
)str
->str.wstr
[i
]);
2360 rd
->data
[2*i
+ 1] = LOBYTE
((WORD
)str
->str.wstr
[i
]);
2363 #ifndef WORDS_BIGENDIAN
2367 for
(i
= 0; i
< str
->size
; i
++)
2369 rd
->data
[2*i
+ 1] = HIBYTE
((WORD
)str
->str.wstr
[i
]);
2370 rd
->data
[2*i
+ 0] = LOBYTE
((WORD
)str
->str.wstr
[i
]);
2376 internal_error
(__FILE__
, __LINE__
, "Invalid stringtype\n");
2380 static raw_data_t
*merge_raw_data
(raw_data_t
*r1
, raw_data_t
*r2
)
2382 r1
->data
= xrealloc
(r1
->data
, r1
->size
+ r2
->size
);
2383 memcpy
(r1
->data
+ r1
->size
, r2
->data
, r2
->size
);
2384 r1
->size
+= r2
->size
;
2388 static raw_data_t
*merge_raw_data_int
(raw_data_t
*r1
, int i
)
2390 raw_data_t
*t
= int2raw_data
(i
);
2391 merge_raw_data
(r1
, t
);
2397 static raw_data_t
*merge_raw_data_long
(raw_data_t
*r1
, int i
)
2399 raw_data_t
*t
= long2raw_data
(i
);
2400 merge_raw_data
(r1
, t
);
2406 static raw_data_t
*merge_raw_data_str
(raw_data_t
*r1
, string_t
*str
)
2408 raw_data_t
*t
= str2raw_data
(str
);
2409 merge_raw_data
(r1
, t
);
2415 /* Function the go back in a list to get the head */
2416 static menu_item_t
*get_item_head
(menu_item_t
*p
)
2425 static resource_t
*get_resource_head
(resource_t
*p
)
2434 static ver_block_t
*get_ver_block_head
(ver_block_t
*p
)
2443 static ver_value_t
*get_ver_value_head
(ver_value_t
*p
)
2452 static control_t
*get_control_head
(control_t
*p
)
2461 static event_t
*get_event_head
(event_t
*p
)
2470 /* Find a stringtable with given language */
2471 static stringtable_t
*find_stringtable
(lvc_t
*lvc
)
2475 assert
(lvc
!= NULL
);
2478 lvc
->language
= dup_language
(currentlanguage
);
2480 for
(stt
= sttres
; stt
; stt
= stt
->next
)
2482 if
(stt
->lvc.language
->id
== lvc
->language
->id
2483 && stt
->lvc.language
->sub
== lvc
->language
->sub
)
2485 /* Found a table with the same language */
2486 /* The version and characteristics are now handled
2487 * in the generation of the individual stringtables.
2488 * This enables localized analysis.
2489 if((stt->lvc.version && lvc->version && *(stt->lvc.version) != *(lvc->version))
2490 || (!stt->lvc.version && lvc->version)
2491 || (stt->lvc.version && !lvc->version))
2492 parser_warning("Stringtable's versions are not the same, using first definition\n");
2494 if((stt->lvc.characts && lvc->characts && *(stt->lvc.characts) != *(lvc->characts))
2495 || (!stt->lvc.characts && lvc->characts)
2496 || (stt->lvc.characts && !lvc->characts))
2497 parser_warning("Stringtable's characteristics are not the same, using first definition\n");
2505 /* qsort sorting function for string table entries */
2506 #define STE(p) ((const stt_entry_t *)(p))
2507 static int sort_stt_entry
(const void *e1
, const void *e2
)
2509 return STE
(e1
)->id
- STE
(e2
)->id
;
2513 static resource_t
*build_stt_resources
(stringtable_t
*stthead
)
2516 stringtable_t
*newstt
;
2518 resource_t
*rsclist
= NULL
;
2519 resource_t
*rsctail
= NULL
;
2524 characts_t
*characts
;
2530 /* For all languages defined */
2531 for
(stt
= stthead
; stt
; stt
= stt
->next
)
2533 assert
(stt
->nentries
> 0);
2535 /* Sort the entries */
2536 if
(stt
->nentries
> 1)
2537 qsort
(stt
->entries
, stt
->nentries
, sizeof
(stt
->entries
[0]), sort_stt_entry
);
2539 for
(i
= 0; i
< stt
->nentries
; )
2541 newstt
= new_stringtable
(&stt
->lvc
);
2542 newstt
->entries
= xmalloc
(16 * sizeof
(stt_entry_t
));
2543 memset
( newstt
->entries
, 0, 16 * sizeof
(stt_entry_t
) );
2544 newstt
->nentries
= 16;
2545 newstt
->idbase
= stt
->entries
[i
].id
& ~
0xf;
2546 for
(j
= 0; j
< 16 && i
< stt
->nentries
; j
++)
2548 if
(stt
->entries
[i
].id
- newstt
->idbase
== j
)
2550 newstt
->entries
[j
] = stt
->entries
[i
];
2558 /* Check individual memory options and get
2559 * the first characteristics/version
2561 for
(j
= 0; j
< 16; j
++)
2563 if
(!newstt
->entries
[j
].str
)
2565 andsum
&= newstt
->entries
[j
].memopt
;
2566 orsum |
= newstt
->entries
[j
].memopt
;
2568 characts
= newstt
->entries
[j
].characts
;
2570 version
= newstt
->entries
[j
].version
;
2574 warning
("Stringtable's memory options are not equal (idbase: %d)\n", newstt
->idbase
);
2576 /* Check version and characteristics */
2577 for
(j
= 0; j
< 16; j
++)
2580 && newstt
->entries
[j
].characts
2581 && *newstt
->entries
[j
].characts
!= *characts
)
2582 warning
("Stringtable's characteristics are not the same (idbase: %d)\n", newstt
->idbase
);
2584 && newstt
->entries
[j
].version
2585 && *newstt
->entries
[j
].version
!= *version
)
2586 warning
("Stringtable's versions are not the same (idbase: %d)\n", newstt
->idbase
);
2588 rsc
= new_resource
(res_stt
, newstt
, newstt
->memopt
, newstt
->lvc.language
);
2589 rsc
->name
= new_name_id
();
2590 rsc
->name
->type
= name_ord
;
2591 rsc
->name
->name.i_name
= (newstt
->idbase
>> 4) + 1;
2592 rsc
->memopt
= andsum
; /* Set to least common denominator */
2593 newstt
->memopt
= andsum
;
2594 newstt
->lvc.characts
= characts
;
2595 newstt
->lvc.version
= version
;
2603 rsctail
->next
= rsc
;
2604 rsc
->prev
= rsctail
;
2613 static toolbar_item_t
*ins_tlbr_button
(toolbar_item_t
*prev
, toolbar_item_t
*idrec
)
2622 static toolbar_item_t
*get_tlbr_buttons_head
(toolbar_item_t
*p
, int *nitems
)
2641 static string_t
*make_filename
(string_t
*str
)
2643 if
(str
->type
== str_char
)
2647 /* Remove escaped backslash and convert to forward */
2648 for
(cptr
= str
->str.cstr
; (cptr
= strchr
(cptr
, '\\')) != NULL
; cptr
++)
2652 memmove
(cptr
, cptr
+1, strlen
(cptr
));
2662 /* Remove escaped backslash and convert to forward */
2663 for
(wptr
= str
->str.wstr
; (wptr
= strchrW
(wptr
, '\\')) != NULL
; wptr
++)
2667 memmove
(wptr
, wptr
+1, strlenW
(wptr
));
2677 * Process all resources to extract fonts and build
2678 * a fontdir resource.
2680 * Note: MS' resource compiler (build 1472) does not
2681 * handle font resources with different languages.
2682 * The fontdir is generated in the last active language
2683 * and font identifiers must be unique across the entire
2685 * This is not logical considering the localization
2686 * constraints of all other resource types. MS has,
2687 * most probably, never testet localized fonts. However,
2688 * using fontresources is rare, so it might not occur
2689 * in normal applications.
2690 * Wine does require better localization because a lot
2691 * of languages are coded into the same executable.
2692 * Therefore, I will generate fontdirs for *each*
2693 * localized set of fonts.
2695 static resource_t
*build_fontdir
(resource_t
**fnt
, int nfnt
)
2697 static int once
= 0;
2700 warning
("Need to parse fonts, not yet implemented (fnt: %p, nfnt: %d)\n", fnt
, nfnt
);
2706 static resource_t
*build_fontdirs
(resource_t
*tail
)
2709 resource_t
*lst
= NULL
;
2710 resource_t
**fnt
= NULL
; /* List of all fonts */
2712 resource_t
**fnd
= NULL
; /* List of all fontdirs */
2714 resource_t
**lanfnt
= NULL
;
2721 nid.type
= name_str
;
2722 nid.name.s_name
= &str
;
2723 str.type
= str_char
;
2724 str.str.cstr
= xstrdup
("FONTDIR");
2727 /* Extract all fonts and fontdirs */
2728 for
(rsc
= tail
; rsc
; rsc
= rsc
->prev
)
2730 if
(rsc
->type
== res_fnt
)
2733 fnt
= xrealloc
(fnt
, nfnt
* sizeof
(*fnt
));
2736 else if
(rsc
->type
== res_fntdir
)
2739 fnd
= xrealloc
(fnd
, nfnd
* sizeof
(*fnd
));
2744 /* Verify the name of the present fontdirs */
2745 for
(i
= 0; i
< nfnd
; i
++)
2747 if
(compare_name_id
(&nid
, fnd
[i
]->name
))
2749 warning
("User supplied FONTDIR entry has an invalid name '%s', ignored\n",
2750 get_nameid_str
(fnd
[i
]->name
));
2759 warning
("Found %d FONTDIR entries without any fonts present\n", nfnd
);
2764 lanfnt
= xmalloc
(nfnt
* sizeof
(*lanfnt
));
2765 memset
( lanfnt
, 0, nfnt
* sizeof
(*lanfnt
));
2767 /* Get all fonts covered by fontdirs */
2768 for
(i
= 0; i
< nfnd
; i
++)
2776 for
(j
= 0; j
< nfnt
; j
++)
2780 if
(fnt
[j
]->lan
->id
== fnd
[i
]->lan
->id
&& fnt
[j
]->lan
->sub
== fnd
[i
]->lan
->sub
)
2782 lanfnt
[nlanfnt
] = fnt
[j
];
2788 cnt
= *(WORD
*)fnd
[i
]->res.fnd
->data
->data
;
2791 else if
(nlanfnt
== BYTESWAP_WORD
(cnt
))
2794 error("FONTDIR for language %d,%d has wrong count (%d, expected %d)\n",
2795 fnd
[i
]->lan
->id
, fnd
[i
]->lan
->sub
, cnt
, nlanfnt
);
2796 #ifdef WORDS_BIGENDIAN
2797 if
((byteorder
== WRC_BO_LITTLE
&& !isswapped
) ||
(byteorder
!= WRC_BO_LITTLE
&& isswapped
))
2799 if
((byteorder
== WRC_BO_BIG
&& !isswapped
) ||
(byteorder
!= WRC_BO_BIG
&& isswapped
))
2802 internal_error
(__FILE__
, __LINE__
, "User supplied FONTDIR needs byteswapping\n");
2806 /* We now have fonts left where we need to make a fontdir resource */
2807 for
(i
= fntleft
= 0; i
< nfnt
; i
++)
2814 /* Get fonts of same language in lanfnt[] */
2815 for
(i
= nlanfnt
= 0; i
< nfnt
; i
++)
2822 lanfnt
[nlanfnt
] = fnt
[i
];
2827 else if
(fnt
[i
]->lan
->id
== lanfnt
[0]->lan
->id
&& fnt
[i
]->lan
->sub
== lanfnt
[0]->lan
->sub
)
2831 /* and build a fontdir */
2832 rsc
= build_fontdir
(lanfnt
, nlanfnt
);
2853 * This gets invoked to determine whether the next resource
2854 * is to be of a standard-type (e.g. bitmaps etc.), or should
2855 * be a user-type resource. This function is required because
2856 * there is the _possibility_ of a lookahead token in the
2857 * parser, which is generated from the "expr" state in the
2860 * The general resource format is:
2861 * <identifier> <type> <flags> <resourcebody>
2863 * The <identifier> can either be tIDENT or "expr". The latter
2864 * will always generate a lookahead, which is the <type> of the
2865 * resource to parse. Otherwise, we need to get a new token from
2866 * the scanner to determine the next step.
2868 * The problem arrises when <type> is numerical. This case should
2869 * map onto default resource-types and be parsed as such instead
2870 * of being mapped onto user-type resources.
2872 * The trick lies in the fact that yacc (bison) doesn't care about
2873 * intermediate changes of the lookahead while reducing a rule. We
2874 * simply replace the lookahead with a token that will result in
2875 * a shift to the appropriate rule for the specific resource-type.
2877 static int rsrcid_to_token
(int lookahead
)
2881 /* Get a token if we don't have one yet */
2882 if
(lookahead
== YYEMPTY
)
2885 /* Only numbers are possibly interesting */
2911 case WRC_RT_FONTDIR
:
2917 case WRC_RT_MESSAGETABLE
:
2918 token
= tMESSAGETABLE
;
2920 case WRC_RT_DLGINIT
:
2923 case WRC_RT_ACCELERATOR
:
2924 token
= tACCELERATORS
;
2932 case WRC_RT_VERSION
:
2933 token
= tVERSIONINFO
;
2935 case WRC_RT_TOOLBAR
:
2945 case WRC_RT_ANICURSOR
:
2946 case WRC_RT_ANIICON
:
2947 case WRC_RT_GROUP_CURSOR
:
2948 case WRC_RT_GROUP_ICON
:
2949 parser_warning
("Usertype uses reserved type ID %d, which is auto-generated\n", yylval.num
);
2952 case WRC_RT_DLGINCLUDE
:
2953 case WRC_RT_PLUGPLAY
:
2955 parser_warning
("Usertype uses reserved type ID %d, which is not supported by wrc yet\n", yylval.num
);