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 menuex_item_t
*get_itemex_head
(menuex_item_t
*p
);
196 static menu_item_t
*get_item_head
(menu_item_t
*p
);
197 static raw_data_t
*merge_raw_data_str
(raw_data_t
*r1
, string_t
*str
);
198 static raw_data_t
*merge_raw_data_int
(raw_data_t
*r1
, int i
);
199 static raw_data_t
*merge_raw_data_long
(raw_data_t
*r1
, int i
);
200 static raw_data_t
*merge_raw_data
(raw_data_t
*r1
, raw_data_t
*r2
);
201 static raw_data_t
*str2raw_data
(string_t
*str
);
202 static raw_data_t
*int2raw_data
(int i
);
203 static raw_data_t
*long2raw_data
(int i
);
204 static raw_data_t
*load_file
(string_t
*name
, language_t
*lang
);
205 static itemex_opt_t
*new_itemex_opt
(int id
, int type
, int state
, int helpid
);
206 static event_t
*add_string_event
(string_t
*key
, int id
, int flags
, event_t
*prev
);
207 static event_t
*add_event
(int key
, int id
, int flags
, event_t
*prev
);
208 static dialogex_t
*dialogex_version
(version_t
*v
, dialogex_t
*dlg
);
209 static dialogex_t
*dialogex_characteristics
(characts_t
*c
, dialogex_t
*dlg
);
210 static dialogex_t
*dialogex_language
(language_t
*l
, dialogex_t
*dlg
);
211 static dialogex_t
*dialogex_menu
(name_id_t
*m
, dialogex_t
*dlg
);
212 static dialogex_t
*dialogex_class
(name_id_t
*n
, dialogex_t
*dlg
);
213 static dialogex_t
*dialogex_font
(font_id_t
*f
, dialogex_t
*dlg
);
214 static dialogex_t
*dialogex_caption
(string_t
*s
, dialogex_t
*dlg
);
215 static dialogex_t
*dialogex_exstyle
(style_t
*st
, dialogex_t
*dlg
);
216 static dialogex_t
*dialogex_style
(style_t
*st
, dialogex_t
*dlg
);
217 static name_id_t
*convert_ctlclass
(name_id_t
*cls
);
218 static control_t
*ins_ctrl
(int type
, int special_style
, control_t
*ctrl
, control_t
*prev
);
219 static dialog_t
*dialog_version
(version_t
*v
, dialog_t
*dlg
);
220 static dialog_t
*dialog_characteristics
(characts_t
*c
, dialog_t
*dlg
);
221 static dialog_t
*dialog_language
(language_t
*l
, dialog_t
*dlg
);
222 static dialog_t
*dialog_menu
(name_id_t
*m
, dialog_t
*dlg
);
223 static dialog_t
*dialog_class
(name_id_t
*n
, dialog_t
*dlg
);
224 static dialog_t
*dialog_font
(font_id_t
*f
, dialog_t
*dlg
);
225 static dialog_t
*dialog_caption
(string_t
*s
, dialog_t
*dlg
);
226 static dialog_t
*dialog_exstyle
(style_t
* st
, dialog_t
*dlg
);
227 static dialog_t
*dialog_style
(style_t
* st
, dialog_t
*dlg
);
228 static resource_t
*build_stt_resources
(stringtable_t
*stthead
);
229 static stringtable_t
*find_stringtable
(lvc_t
*lvc
);
230 static toolbar_item_t
*ins_tlbr_button
(toolbar_item_t
*prev
, toolbar_item_t
*idrec
);
231 static toolbar_item_t
*get_tlbr_buttons_head
(toolbar_item_t
*p
, int *nitems
);
232 static string_t
*make_filename
(string_t
*s
);
233 static resource_t
*build_fontdirs
(resource_t
*tail
);
234 static resource_t
*build_fontdir
(resource_t
**fnt
, int nfnt
);
235 static int rsrcid_to_token
(int lookahead
);
267 menuex_item_t
*menexitm
;
275 toolbar_item_t
*tlbarItems
;
277 style_pair_t
*styles
;
283 %token
<num
> tNUMBER tLNUMBER
284 %token
<str
> tSTRING tIDENT tFILENAME
285 %token
<raw
> tRAWDATA
286 %token tACCELERATORS tBITMAP tCURSOR tDIALOG tDIALOGEX tMENU tMENUEX tMESSAGETABLE
287 %token tRCDATA tVERSIONINFO tSTRINGTABLE tFONT tFONTDIR tICON tHTML
288 %token tAUTO3STATE tAUTOCHECKBOX tAUTORADIOBUTTON tCHECKBOX tDEFPUSHBUTTON
289 %token tPUSHBUTTON tRADIOBUTTON tSTATE3
/* PUSHBOX */
290 %token tGROUPBOX tCOMBOBOX tLISTBOX tSCROLLBAR
291 %token tCONTROL tEDITTEXT
292 %token tRTEXT tCTEXT tLTEXT
294 %token tSHIFT tALT tASCII tVIRTKEY tGRAYED tCHECKED tINACTIVE tNOINVERT
295 %token tPURE tIMPURE tDISCARDABLE tLOADONCALL tPRELOAD tFIXED tMOVEABLE
296 %token tCLASS tCAPTION tCHARACTERISTICS tEXSTYLE tSTYLE tVERSION tLANGUAGE
297 %token tFILEVERSION tPRODUCTVERSION tFILEFLAGSMASK tFILEOS tFILETYPE tFILEFLAGS tFILESUBTYPE
298 %token tMENUBARBREAK tMENUBREAK tMENUITEM tPOPUP tSEPARATOR
300 %token tTOOLBAR tBUTTON
311 %type
<res
> resource_file resource resources resource_definition
312 %type
<stt
> stringtable strings
315 %type
<acc
> accelerators
318 %type
<ani
> cursor icon
319 %type
<dlg
> dialog dlg_attributes
320 %type
<ctl
> ctrls gen_ctrl lab_ctrl ctrl_desc iconinfo
322 %type
<dlgex
> dialogex dlgex_attribs
323 %type
<ctl
> exctrls gen_exctrl lab_exctrl exctrl_desc
326 %type
<raw
> raw_data raw_elements opt_data file_raw
327 %type
<veri
> versioninfo fix_version
328 %type
<verw
> ver_words
329 %type
<blk
> ver_blocks ver_block
330 %type
<val
> ver_values ver_value
332 %type
<menitm
> item_definitions menu_body
334 %type
<menexitm
> itemex_definitions menuex_body
335 %type
<exopt
> itemex_p_options itemex_options
336 %type
<msg
> messagetable
338 %type
<num
> item_options
339 %type
<nid
> nameid nameid_s ctlclass usertype
340 %type
<num
> acc_opt acc accs
341 %type
<iptr
> loadmemopts lamo lama
342 %type
<fntid
> opt_font opt_exfont opt_expr
344 %type
<lan
> opt_language
345 %type
<chars
> opt_characts
346 %type
<ver
> opt_version
349 %type
<tlbar
> toolbar
350 %type
<tlbarItems
> toolbar_items
351 %type
<dginit
> dlginit
352 %type
<styles
> optional_style_pair
361 resource_t
*rsc
, *head
;
362 /* First add stringtables to the resource-list */
363 rsc
= build_stt_resources
(sttres
);
364 /* 'build_stt_resources' returns a head and $1 is a tail */
373 /* Find the tail again */
374 while
($1 && $1->next
)
376 /* Now add any fontdirecory */
377 rsc
= build_fontdirs
($1);
378 /* 'build_fontdir' returns a head and $1 is a tail */
388 /* Final statements before were done */
389 if
((head
= get_resource_head
($1)) != NULL
)
391 if
(resource_top
) /* append to existing resources */
393 resource_t
*tail
= resource_top
;
394 while
(tail
->next
) tail
= tail
->next
;
398 else resource_top
= head
;
404 /* Resources are put into a linked list */
406 : /* Empty */ { $$
= NULL
; want_id
= 1; }
407 | resources resource
{
410 resource_t
*tail
= $2;
411 resource_t
*head
= $2;
420 /* Check for duplicate identifiers */
423 resource_t
*rsc
= $1;
426 if
(rsc
->type
== head
->type
427 && rsc
->lan
->id
== head
->lan
->id
428 && rsc
->lan
->sub
== head
->lan
->sub
429 && !compare_name_id
(rsc
->name
, head
->name
)
430 && (rsc
->type
!= res_usr ||
!compare_name_id
(rsc
->res.usr
->type
,head
->res.usr
->type
)))
432 yyerror("Duplicate resource name '%s'", get_nameid_str
(rsc
->name
));
441 resource_t
*tail
= $1;
449 if
(!dont_want_id
) /* See comments in language parsing below */
454 * The following newline rule will never get reduced because we never
455 * get the tNL token, unless we explicitly set the 'want_nl'
456 * flag, which we don't.
457 * The *ONLY* reason for this to be here is because Berkeley
458 * yacc (byacc), at least version 1.9, has a bug.
459 * (identified in the generated parser on the second
461 * static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93";
463 * This extra rule fixes it.
464 * The problem is that the expression handling rule "expr: xpr"
465 * is not reduced on non-terminal tokens, defined above in the
466 * %token declarations. Token tNL is the only non-terminal that
467 * can occur. The error becomes visible in the language parsing
468 * rule below, which looks at the look-ahead token and tests it
469 * for tNL. However, byacc already generates an error upon reading
470 * the token instead of keeping it as a lookahead. The reason
471 * lies in the lack of a $default transition in the "expr : xpr . "
472 * state (currently state 25). It is probably omitted because tNL
473 * is a non-terminal and the state contains 2 s/r conflicts. The
474 * state enumerates all possible transitions instead of using a
475 * $default transition.
476 * All in all, it is a bug in byacc. (period)
482 /* Parse top level resource definitions etc. */
484 : expr usrcvt resource_definition
{
488 if
($1 > 65535 ||
$1 < -32768)
489 yyerror("Resource's ID out of range (%d)", $1);
490 $$
->name
= new_name_id
();
491 $$
->name
->type
= name_ord
;
492 $$
->name
->name.i_name
= $1;
493 chat
("Got %s (%d)\n", get_typename
($3), $$
->name
->name.i_name
);
496 | tIDENT usrcvt resource_definition
{
500 $$
->name
= new_name_id
();
501 $$
->name
->type
= name_str
;
502 $$
->name
->name.s_name
= $1;
503 chat
("Got %s (%s)\n", get_typename
($3), $$
->name
->name.s_name
->str.cstr
);
507 /* Don't do anything, stringtables are converted to
508 * resource_t structures when we are finished parsing and
509 * the final rule of the parser is reduced (see above)
512 chat
("Got STRINGTABLE\n");
514 | tLANGUAGE
{want_nl
= 1; } expr
',' expr
{
515 /* We *NEED* the newline to delimit the expression.
516 * Otherwise, we would not be able to set the next
517 * want_id anymore because of the token-lookahead.
519 * However, we can test the lookahead-token for
520 * being "non-expression" type, in which case we
521 * continue. Fortunately, tNL is the only token that
522 * will break expression parsing and is implicitly
523 * void, so we just remove it. This scheme makes it
524 * possible to do some (not all) fancy preprocessor
526 * BTW, we also need to make sure that the next
527 * reduction of 'resources' above will *not* set
528 * want_id because we already have a lookahead that
531 if
(yychar != YYEMPTY
&& yychar != tNL
)
535 yychar = YYEMPTY
; /* Could use 'yyclearin', but we already need the*/
536 /* direct access to yychar in rule 'usrcvt' below. */
537 else if
(yychar == tIDENT
)
538 parser_warning
("LANGUAGE statement not delimited with newline; next identifier might be wrong\n");
540 want_nl
= 0; /* We don't want it anymore if we didn't get it */
543 parser_warning
("LANGUAGE not supported in 16-bit mode\n");
544 free
(currentlanguage
);
545 if
(get_language_codepage
($3, $5) == -1)
546 yyerror( "Language %04x is not supported", ($5<<10) + $3);
547 currentlanguage
= new_language
($3, $5);
549 chat
("Got LANGUAGE %d,%d (0x%04x)\n", $3, $5, ($5<<10) + $3);
554 * Remapping of numerical resource types
555 * (see also comment of called function below)
557 usrcvt
: /* Empty */ { yychar = rsrcid_to_token
(yychar); }
561 * Get a valid name/id
564 if
($1 > 65535 ||
$1 < -32768)
565 yyerror("Resource's ID out of range (%d)", $1);
568 $$
->name.i_name
= $1;
573 $$
->name.s_name
= $1;
578 * Extra string recognition for CLASS statement in dialogs
580 nameid_s: nameid
{ $$
= $1; }
584 $$
->name.s_name
= $1;
588 /* get the value for a single resource*/
590 : accelerators
{ $$
= new_resource
(res_acc
, $1, $1->memopt
, $1->lvc.language
); }
591 | bitmap
{ $$
= new_resource
(res_bmp
, $1, $1->memopt
, $1->data
->lvc.language
); }
594 if
($1->type
== res_anicur
)
596 $$
= rsc
= new_resource
(res_anicur
, $1->u.ani
, $1->u.ani
->memopt
, $1->u.ani
->data
->lvc.language
);
598 else if
($1->type
== res_curg
)
601 $$
= rsc
= new_resource
(res_curg
, $1->u.curg
, $1->u.curg
->memopt
, $1->u.curg
->lvc.language
);
602 for
(cur
= $1->u.curg
->cursorlist
; cur
; cur
= cur
->next
)
604 rsc
->prev
= new_resource
(res_cur
, cur
, $1->u.curg
->memopt
, $1->u.curg
->lvc.language
);
605 rsc
->prev
->next
= rsc
;
607 rsc
->name
= new_name_id
();
608 rsc
->name
->type
= name_ord
;
609 rsc
->name
->name.i_name
= cur
->id
;
613 internal_error
(__FILE__
, __LINE__
, "Invalid top-level type %d in cursor resource\n", $1->type
);
616 | dialog
{ $$
= new_resource
(res_dlg
, $1, $1->memopt
, $1->lvc.language
); }
619 $$
= new_resource
(res_dlgex
, $1, $1->memopt
, $1->lvc.language
);
623 | dlginit
{ $$
= new_resource
(res_dlginit
, $1, $1->memopt
, $1->data
->lvc.language
); }
624 | font
{ $$
= new_resource
(res_fnt
, $1, $1->memopt
, $1->data
->lvc.language
); }
625 | fontdir
{ $$
= new_resource
(res_fntdir
, $1, $1->memopt
, $1->data
->lvc.language
); }
628 if
($1->type
== res_aniico
)
630 $$
= rsc
= new_resource
(res_aniico
, $1->u.ani
, $1->u.ani
->memopt
, $1->u.ani
->data
->lvc.language
);
632 else if
($1->type
== res_icog
)
635 $$
= rsc
= new_resource
(res_icog
, $1->u.icog
, $1->u.icog
->memopt
, $1->u.icog
->lvc.language
);
636 for
(ico
= $1->u.icog
->iconlist
; ico
; ico
= ico
->next
)
638 rsc
->prev
= new_resource
(res_ico
, ico
, $1->u.icog
->memopt
, $1->u.icog
->lvc.language
);
639 rsc
->prev
->next
= rsc
;
641 rsc
->name
= new_name_id
();
642 rsc
->name
->type
= name_ord
;
643 rsc
->name
->name.i_name
= ico
->id
;
647 internal_error
(__FILE__
, __LINE__
, "Invalid top-level type %d in icon resource\n", $1->type
);
650 | menu
{ $$
= new_resource
(res_men
, $1, $1->memopt
, $1->lvc.language
); }
653 $$
= new_resource
(res_menex
, $1, $1->memopt
, $1->lvc.language
);
657 | messagetable
{ $$
= new_resource
(res_msg
, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE
, $1->data
->lvc.language
); }
658 | html
{ $$
= new_resource
(res_html
, $1, $1->memopt
, $1->data
->lvc.language
); }
659 | rcdata
{ $$
= new_resource
(res_rdt
, $1, $1->memopt
, $1->data
->lvc.language
); }
660 | toolbar
{ $$
= new_resource
(res_toolbar
, $1, $1->memopt
, $1->lvc.language
); }
661 | userres
{ $$
= new_resource
(res_usr
, $1, $1->memopt
, $1->data
->lvc.language
); }
662 | versioninfo
{ $$
= new_resource
(res_ver
, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE
, $1->lvc.language
); }
666 filename: tFILENAME
{ $$
= make_filename
($1); }
667 | tIDENT
{ $$
= make_filename
($1); }
668 | tSTRING
{ $$
= make_filename
($1); }
671 /* ------------------------------ Bitmap ------------------------------ */
672 bitmap
: tBITMAP loadmemopts file_raw
{ $$
= new_bitmap
($3, $2); }
675 /* ------------------------------ Cursor ------------------------------ */
676 cursor
: tCURSOR loadmemopts file_raw
{
678 if
($3->size
> 4 && !memcmp
($3->data
, riff
, sizeof
(riff
)))
680 $$
->type
= res_anicur
;
681 $$
->u.ani
= new_ani_curico
(res_anicur
, $3, $2);
686 $$
->u.curg
= new_cursor_group
($3, $2);
691 /* ------------------------------ Icon ------------------------------ */
692 icon
: tICON loadmemopts file_raw
{
694 if
($3->size
> 4 && !memcmp
($3->data
, riff
, sizeof
(riff
)))
696 $$
->type
= res_aniico
;
697 $$
->u.ani
= new_ani_curico
(res_aniico
, $3, $2);
702 $$
->u.icog
= new_icon_group
($3, $2);
707 /* ------------------------------ Font ------------------------------ */
709 * The reading of raw_data for fonts is a Borland BRC
710 * extension. MS generates an error. However, it is
711 * most logical to support this, considering how wine
712 * enters things in CVS (ascii).
714 font
: tFONT loadmemopts file_raw
{ $$
= new_font
($3, $2); }
718 * The fontdir is a Borland BRC extension which only
719 * reads the data as 'raw_data' from the file.
720 * I don't know whether it is interpreted.
721 * The fontdir is generated if it was not present and
722 * fonts are defined in the source.
724 fontdir
: tFONTDIR loadmemopts file_raw
{ $$
= new_fontdir
($3, $2); }
727 /* ------------------------------ MessageTable ------------------------------ */
728 /* It might be interesting to implement the MS Message compiler here as well
729 * to get everything in one source. Might be a future project.
732 : tMESSAGETABLE loadmemopts file_raw
{
734 parser_warning
("MESSAGETABLE not supported in 16-bit mode\n");
735 $$
= new_messagetable
($3, $2);
739 /* ------------------------------ HTML ------------------------------ */
740 html
: tHTML loadmemopts file_raw
{ $$
= new_html
($3, $2); }
743 /* ------------------------------ RCData ------------------------------ */
744 rcdata
: tRCDATA loadmemopts file_raw
{ $$
= new_rcdata
($3, $2); }
747 /* ------------------------------ DLGINIT ------------------------------ */
748 dlginit
: tDLGINIT loadmemopts file_raw
{ $$
= new_dlginit
($3, $2); }
751 /* ------------------------------ UserType ------------------------------ */
752 userres
: usertype loadmemopts file_raw
{
753 #ifdef WORDS_BIGENDIAN
754 if
(pedantic
&& byteorder
!= WRC_BO_LITTLE
)
756 if
(pedantic
&& byteorder
== WRC_BO_BIG
)
758 parser_warning
("Byteordering is not little-endian and type cannot be interpreted\n");
759 $$
= new_user
($1, $3, $2);
766 $$
->name.i_name
= $1;
771 $$
->name.s_name
= $1;
775 /* ------------------------------ Accelerator ------------------------------ */
777 : tACCELERATORS loadmemopts opt_lvc tBEGIN events tEND
{
778 $$
= new_accelerator
();
786 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE
;
789 yyerror("Accelerator table must have at least one entry");
790 $$
->events
= get_event_head
($5);
796 if
(!$$
->lvc.language
)
797 $$
->lvc.language
= dup_language
(currentlanguage
);
801 events
: /* Empty */ { $$
=NULL
; }
802 | events tSTRING
',' expr acc_opt
{ $$
=add_string_event
($2, $4, $5, $1); }
803 | events expr
',' expr acc_opt
{ $$
=add_event
($2, $4, $5, $1); }
807 * The empty rule generates a s/r conflict because of {bi,u}nary expr
808 * on - and +. It cannot be solved in any way because it is the same as
809 * the if/then/else problem (LALR(1) problem). The conflict is moved
810 * away by forcing it to be in the expression handling below.
812 acc_opt
: /* Empty */ { $$
= 0; }
813 |
',' accs
{ $$
= $2; }
816 accs
: acc
{ $$
= $1; }
817 | accs
',' acc
{ $$
= $1 |
$3; }
820 acc
: tNOINVERT
{ $$
= WRC_AF_NOINVERT
; }
821 | tSHIFT
{ $$
= WRC_AF_SHIFT
; }
822 | tCONTROL
{ $$
= WRC_AF_CONTROL
; }
823 | tALT
{ $$
= WRC_AF_ALT
; }
824 | tASCII
{ $$
= WRC_AF_ASCII
; }
825 | tVIRTKEY
{ $$
= WRC_AF_VIRTKEY
; }
828 /* ------------------------------ Dialog ------------------------------ */
829 /* FIXME: Support EXSTYLE in the dialog line itself */
830 dialog
: tDIALOG loadmemopts expr
',' expr
',' expr
',' expr dlg_attributes
838 $10->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
843 $10->controls
= get_control_head
($12);
847 $$
->style
= new_style
(0,0);
848 $$
->style
->or_mask
= WS_POPUP
;
852 $$
->style
->or_mask |
= WS_CAPTION
;
854 $$
->style
->or_mask |
= DS_SETFONT
;
856 $$
->style
->or_mask
&= ~
($$
->style
->and_mask
);
857 $$
->style
->and_mask
= 0;
859 if
(!$$
->lvc.language
)
860 $$
->lvc.language
= dup_language
(currentlanguage
);
865 : /* Empty */ { $$
=new_dialog
(); }
866 | dlg_attributes tSTYLE style
{ $$
=dialog_style
($3,$1); }
867 | dlg_attributes tEXSTYLE style
{ $$
=dialog_exstyle
($3,$1); }
868 | dlg_attributes tCAPTION tSTRING
{ $$
=dialog_caption
($3,$1); }
869 | dlg_attributes opt_font
{ $$
=dialog_font
($2,$1); }
870 | dlg_attributes tCLASS nameid_s
{ $$
=dialog_class
($3,$1); }
871 | dlg_attributes tMENU nameid
{ $$
=dialog_menu
($3,$1); }
872 | dlg_attributes opt_language
{ $$
=dialog_language
($2,$1); }
873 | dlg_attributes opt_characts
{ $$
=dialog_characteristics
($2,$1); }
874 | dlg_attributes opt_version
{ $$
=dialog_version
($2,$1); }
877 ctrls
: /* Empty */ { $$
= NULL
; }
878 | ctrls tCONTROL gen_ctrl
{ $$
=ins_ctrl
(-1, 0, $3, $1); }
879 | ctrls tEDITTEXT ctrl_desc
{ $$
=ins_ctrl
(CT_EDIT
, 0, $3, $1); }
880 | ctrls tLISTBOX ctrl_desc
{ $$
=ins_ctrl
(CT_LISTBOX
, 0, $3, $1); }
881 | ctrls tCOMBOBOX ctrl_desc
{ $$
=ins_ctrl
(CT_COMBOBOX
, 0, $3, $1); }
882 | ctrls tSCROLLBAR ctrl_desc
{ $$
=ins_ctrl
(CT_SCROLLBAR
, 0, $3, $1); }
883 | ctrls tCHECKBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_CHECKBOX
, $3, $1); }
884 | ctrls tDEFPUSHBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_DEFPUSHBUTTON
, $3, $1); }
885 | ctrls tGROUPBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_GROUPBOX
, $3, $1);}
886 | ctrls tPUSHBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_PUSHBUTTON
, $3, $1); }
887 /* | ctrls tPUSHBOX lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
888 | ctrls tRADIOBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_RADIOBUTTON
, $3, $1); }
889 | ctrls tAUTO3STATE lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTO3STATE
, $3, $1); }
890 | ctrls tSTATE3 lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_3STATE
, $3, $1); }
891 | ctrls tAUTOCHECKBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTOCHECKBOX
, $3, $1); }
892 | ctrls tAUTORADIOBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTORADIOBUTTON
, $3, $1); }
893 | ctrls tLTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_LEFT
, $3, $1); }
894 | ctrls tCTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_CENTER
, $3, $1); }
895 | ctrls tRTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_RIGHT
, $3, $1); }
896 /* special treatment for icons, as the extent is optional */
897 | ctrls tICON nameid_s opt_comma expr
',' expr
',' expr iconinfo
{
902 $$
= ins_ctrl
(CT_STATIC
, SS_ICON
, $10, $1);
907 : nameid_s opt_comma expr
',' expr
',' expr
',' expr
',' expr optional_style_pair
{
917 $$
->style
= $12->style
;
921 $$
->exstyle
= $12->exstyle
;
922 $$
->gotexstyle
= TRUE
;
930 : expr
',' expr
',' expr
',' expr
',' expr optional_style_pair
{
939 $$
->style
= $10->style
;
943 $$
->exstyle
= $10->exstyle
;
944 $$
->gotexstyle
= TRUE
;
951 iconinfo: /* Empty */
952 { $$
= new_control
(); }
954 |
',' expr
',' expr
{
959 |
',' expr
',' expr
',' style
{
966 |
',' expr
',' expr
',' style
',' style
{
973 $$
->gotexstyle
= TRUE
;
977 gen_ctrl: nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr
',' style
{
981 $$
->ctlclass
= convert_ctlclass
($5);
989 $$
->gotexstyle
= TRUE
;
991 | nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr
{
995 $$
->ctlclass
= convert_ctlclass
($5);
1006 : tFONT expr
',' tSTRING
{ $$
= new_font_id
($2, $4, 0, 0); }
1009 /* ------------------------------ style flags ------------------------------ */
1011 : /* Empty */ { $$
= NULL
; }
1012 |
',' style
{ $$
= new_style_pair
($2, 0); }
1013 |
',' style
',' style
{ $$
= new_style_pair
($2, $4); }
1017 : style
'|' style
{ $$
= new_style
($1->or_mask |
$3->or_mask
, $1->and_mask |
$3->and_mask
); free
($1); free
($3);}
1018 |
'(' style
')' { $$
= $2; }
1019 | any_num
{ $$
= new_style
($1, 0); }
1020 | tNOT any_num
{ $$
= new_style
(0, $2); }
1026 $$
->type
= name_ord
;
1027 $$
->name.i_name
= $1;
1031 $$
->type
= name_str
;
1032 $$
->name.s_name
= $1;
1036 /* ------------------------------ DialogEx ------------------------------ */
1037 dialogex: tDIALOGEX loadmemopts expr
',' expr
',' expr
',' expr helpid dlgex_attribs
1038 tBEGIN exctrls tEND
{
1040 parser_warning
("DIALOGEX not supported in 16-bit mode\n");
1043 $11->memopt
= *($2);
1047 $11->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1054 $11->helpid
= *($10);
1055 $11->gothelpid
= TRUE
;
1058 $11->controls
= get_control_head
($13);
1061 assert
($$
->style
!= NULL
);
1064 $$
->style
->or_mask
= WS_POPUP
;
1065 $$
->gotstyle
= TRUE
;
1068 $$
->style
->or_mask |
= WS_CAPTION
;
1070 $$
->style
->or_mask |
= DS_SETFONT
;
1072 $$
->style
->or_mask
&= ~
($$
->style
->and_mask
);
1073 $$
->style
->and_mask
= 0;
1075 if
(!$$
->lvc.language
)
1076 $$
->lvc.language
= dup_language
(currentlanguage
);
1081 : /* Empty */ { $$
=new_dialogex
(); }
1082 | dlgex_attribs tSTYLE style
{ $$
=dialogex_style
($3,$1); }
1083 | dlgex_attribs tEXSTYLE style
{ $$
=dialogex_exstyle
($3,$1); }
1084 | dlgex_attribs tCAPTION tSTRING
{ $$
=dialogex_caption
($3,$1); }
1085 | dlgex_attribs opt_font
{ $$
=dialogex_font
($2,$1); }
1086 | dlgex_attribs opt_exfont
{ $$
=dialogex_font
($2,$1); }
1087 | dlgex_attribs tCLASS nameid_s
{ $$
=dialogex_class
($3,$1); }
1088 | dlgex_attribs tMENU nameid
{ $$
=dialogex_menu
($3,$1); }
1089 | dlgex_attribs opt_language
{ $$
=dialogex_language
($2,$1); }
1090 | dlgex_attribs opt_characts
{ $$
=dialogex_characteristics
($2,$1); }
1091 | dlgex_attribs opt_version
{ $$
=dialogex_version
($2,$1); }
1094 exctrls
: /* Empty */ { $$
= NULL
; }
1095 | exctrls tCONTROL gen_exctrl
{ $$
=ins_ctrl
(-1, 0, $3, $1); }
1096 | exctrls tEDITTEXT exctrl_desc
{ $$
=ins_ctrl
(CT_EDIT
, 0, $3, $1); }
1097 | exctrls tLISTBOX exctrl_desc
{ $$
=ins_ctrl
(CT_LISTBOX
, 0, $3, $1); }
1098 | exctrls tCOMBOBOX exctrl_desc
{ $$
=ins_ctrl
(CT_COMBOBOX
, 0, $3, $1); }
1099 | exctrls tSCROLLBAR exctrl_desc
{ $$
=ins_ctrl
(CT_SCROLLBAR
, 0, $3, $1); }
1100 | exctrls tCHECKBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_CHECKBOX
, $3, $1); }
1101 | exctrls tDEFPUSHBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_DEFPUSHBUTTON
, $3, $1); }
1102 | exctrls tGROUPBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_GROUPBOX
, $3, $1);}
1103 | exctrls tPUSHBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_PUSHBUTTON
, $3, $1); }
1104 /* | exctrls tPUSHBOX lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
1105 | exctrls tRADIOBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_RADIOBUTTON
, $3, $1); }
1106 | exctrls tAUTO3STATE lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTO3STATE
, $3, $1); }
1107 | exctrls tSTATE3 lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_3STATE
, $3, $1); }
1108 | exctrls tAUTOCHECKBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTOCHECKBOX
, $3, $1); }
1109 | exctrls tAUTORADIOBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTORADIOBUTTON
, $3, $1); }
1110 | exctrls tLTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_LEFT
, $3, $1); }
1111 | exctrls tCTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_CENTER
, $3, $1); }
1112 | exctrls tRTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_RIGHT
, $3, $1); }
1113 /* special treatment for icons, as the extent is optional */
1114 | exctrls tICON nameid_s opt_comma expr
',' expr
',' expr iconinfo
{
1119 $$
= ins_ctrl
(CT_STATIC
, SS_ICON
, $10, $1);
1124 : nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
','
1125 expr
',' style helpid opt_data
{
1129 $$
->ctlclass
= convert_ctlclass
($5);
1131 $$
->gotstyle
= TRUE
;
1139 $$
->gotexstyle
= TRUE
;
1143 $$
->helpid
= *($18);
1144 $$
->gothelpid
= TRUE
;
1149 | nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr opt_data
{
1154 $$
->gotstyle
= TRUE
;
1155 $$
->ctlclass
= convert_ctlclass
($5);
1165 : nameid_s opt_comma expr
',' expr
',' expr
',' expr
',' expr optional_style_pair helpid opt_data
{
1175 $$
->style
= $12->style
;
1176 $$
->gotstyle
= TRUE
;
1180 $$
->exstyle
= $12->exstyle
;
1181 $$
->gotexstyle
= TRUE
;
1191 : expr
',' expr
',' expr
',' expr
',' expr optional_style_pair helpid opt_data
{
1200 $$
->style
= $10->style
;
1201 $$
->gotstyle
= TRUE
;
1205 $$
->exstyle
= $10->exstyle
;
1206 $$
->gotexstyle
= TRUE
;
1214 opt_data: /* Empty */ { $$
= NULL
; }
1215 | raw_data
{ $$
= $1; }
1218 helpid
: /* Empty */ { $$
= NULL
; }
1219 |
',' expr
{ $$
= new_int
($2); }
1223 : tFONT expr
',' tSTRING
',' expr
',' expr opt_expr
{ $$
= new_font_id
($2, $4, $6, $8); }
1227 * FIXME: This odd expression is here to nullify an extra token found
1228 * in some appstudio produced resources which appear to do nothing.
1230 opt_expr: /* Empty */ { $$
= NULL
; }
1231 |
',' expr
{ $$
= NULL
; }
1234 /* ------------------------------ Menu ------------------------------ */
1235 menu
: tMENU loadmemopts opt_lvc menu_body
{
1237 yyerror("Menu must contain items");
1245 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1246 $$
->items
= get_item_head
($4);
1252 if
(!$$
->lvc.language
)
1253 $$
->lvc.language
= dup_language
(currentlanguage
);
1258 : tBEGIN item_definitions tEND
{ $$
= $2; }
1262 : /* Empty */ {$$
= NULL
;}
1263 | item_definitions tMENUITEM tSTRING opt_comma expr item_options
{
1272 | item_definitions tMENUITEM tSEPARATOR
{
1278 | item_definitions tPOPUP tSTRING item_options menu_body
{
1279 $$
= new_menu_item
();
1283 $$
->popup
= get_item_head
($5);
1288 /* NOTE: item_options is right recursive because it would introduce
1289 * a shift/reduce conflict on ',' in itemex_options due to the
1290 * empty rule here. The parser is now forced to look beyond the ','
1291 * before reducing (force shift).
1292 * Right recursion here is not a problem because we cannot expect
1293 * more than 7 parserstack places to be occupied while parsing this
1294 * (who would want to specify a MF_x flag twice?).
1297 : /* Empty */ { $$
= 0; }
1298 | opt_comma tCHECKED item_options
{ $$
= $3 | MF_CHECKED
; }
1299 | opt_comma tGRAYED item_options
{ $$
= $3 | MF_GRAYED
; }
1300 | opt_comma tHELP item_options
{ $$
= $3 | MF_HELP
; }
1301 | opt_comma tINACTIVE item_options
{ $$
= $3 | MF_DISABLED
; }
1302 | opt_comma tMENUBARBREAK item_options
{ $$
= $3 | MF_MENUBARBREAK
; }
1303 | opt_comma tMENUBREAK item_options
{ $$
= $3 | MF_MENUBREAK
; }
1306 /* ------------------------------ MenuEx ------------------------------ */
1307 menuex
: tMENUEX loadmemopts opt_lvc menuex_body
{
1309 parser_warning
("MENUEX not supported in 16-bit mode\n");
1311 yyerror("MenuEx must contain items");
1319 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1320 $$
->items
= get_itemex_head
($4);
1326 if
(!$$
->lvc.language
)
1327 $$
->lvc.language
= dup_language
(currentlanguage
);
1332 : tBEGIN itemex_definitions tEND
{ $$
= $2; }
1336 : /* Empty */ {$$
= NULL
; }
1337 | itemex_definitions tMENUITEM tSTRING itemex_options
{
1338 $$
= new_menuex_item
();
1344 $$
->type
= $4->type
;
1345 $$
->state
= $4->state
;
1346 $$
->helpid
= $4->helpid
;
1347 $$
->gotid
= $4->gotid
;
1348 $$
->gottype
= $4->gottype
;
1349 $$
->gotstate
= $4->gotstate
;
1350 $$
->gothelpid
= $4->gothelpid
;
1353 | itemex_definitions tMENUITEM tSEPARATOR
{
1354 $$
= new_menuex_item
();
1359 | itemex_definitions tPOPUP tSTRING itemex_p_options menuex_body
{
1360 $$
= new_menuex_item
();
1364 $$
->popup
= get_itemex_head
($5);
1367 $$
->type
= $4->type
;
1368 $$
->state
= $4->state
;
1369 $$
->helpid
= $4->helpid
;
1370 $$
->gotid
= $4->gotid
;
1371 $$
->gottype
= $4->gottype
;
1372 $$
->gotstate
= $4->gotstate
;
1373 $$
->gothelpid
= $4->gothelpid
;
1379 : /* Empty */ { $$
= new_itemex_opt
(0, 0, 0, 0); }
1381 $$
= new_itemex_opt
($2, 0, 0, 0);
1384 |
',' e_expr
',' e_expr item_options
{
1385 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $5, 0);
1388 $$
->gotstate
= TRUE
;
1392 |
',' e_expr
',' e_expr
',' expr
{
1393 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6, 0);
1396 $$
->gotstate
= TRUE
;
1403 : /* Empty */ { $$
= new_itemex_opt
(0, 0, 0, 0); }
1405 $$
= new_itemex_opt
($2, 0, 0, 0);
1408 |
',' e_expr
',' expr
{
1409 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4, 0, 0);
1414 |
',' e_expr
',' e_expr
',' expr
{
1415 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6, 0);
1420 $$
->gotstate
= TRUE
;
1422 |
',' e_expr
',' e_expr
',' e_expr
',' expr
{
1423 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6 ?
*($6) : 0, $8);
1429 $$
->gotstate
= TRUE
;
1430 $$
->gothelpid
= TRUE
;
1434 /* ------------------------------ StringTable ------------------------------ */
1435 /* Stringtables are parsed differently than other resources because their
1436 * layout is substantially different from other resources.
1437 * The table is parsed through a _global_ variable 'tagstt' which holds the
1438 * current stringtable descriptor (stringtable_t *) and 'sttres' that holds a
1439 * list of stringtables of different languages.
1442 : stt_head tBEGIN strings tEND
{
1445 yyerror("Stringtable must have at least one entry");
1450 /* Check if we added to a language table or created
1453 for
(stt
= sttres
; stt
; stt
= stt
->next
)
1460 /* It is a new one */
1463 sttres
->prev
= tagstt
;
1464 tagstt
->next
= sttres
;
1470 /* Else were done */
1472 free
(tagstt_memopt
);
1473 tagstt_memopt
= NULL
;
1479 /* This is to get the language of the currently parsed stringtable */
1480 stt_head: tSTRINGTABLE loadmemopts opt_lvc
{
1481 if
((tagstt
= find_stringtable
($3)) == NULL
)
1482 tagstt
= new_stringtable
($3);
1484 tagstt_version
= $3->version
;
1485 tagstt_characts
= $3->characts
;
1490 strings
: /* Empty */ { $$
= NULL
; }
1491 | strings expr opt_comma tSTRING
{
1493 assert
(tagstt
!= NULL
);
1494 if
($2 > 65535 ||
$2 < -32768)
1495 yyerror("Stringtable entry's ID out of range (%d)", $2);
1496 /* Search for the ID */
1497 for
(i
= 0; i
< tagstt
->nentries
; i
++)
1499 if
(tagstt
->entries
[i
].id
== $2)
1500 yyerror("Stringtable ID %d already in use", $2);
1502 /* If we get here, then we have a new unique entry */
1504 tagstt
->entries
= xrealloc
(tagstt
->entries
, sizeof
(tagstt
->entries
[0]) * tagstt
->nentries
);
1505 tagstt
->entries
[tagstt
->nentries
-1].id
= $2;
1506 tagstt
->entries
[tagstt
->nentries
-1].str
= $4;
1508 tagstt
->entries
[tagstt
->nentries
-1].memopt
= *tagstt_memopt
;
1510 tagstt
->entries
[tagstt
->nentries
-1].memopt
= WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE
;
1511 tagstt
->entries
[tagstt
->nentries
-1].version
= tagstt_version
;
1512 tagstt
->entries
[tagstt
->nentries
-1].characts
= tagstt_characts
;
1514 if
(pedantic
&& !$4->size
)
1515 parser_warning
("Zero length strings make no sense\n");
1516 if
(!win32
&& $4->size
> 254)
1517 yyerror("Stringtable entry more than 254 characters");
1518 if
(win32
&& $4->size
> 65534) /* Hmm..., does this happen? */
1519 yyerror("Stringtable entry more than 65534 characters (probably something else that went wrong)");
1524 opt_comma
/* There seem to be two ways to specify a stringtable... */
1529 /* ------------------------------ VersionInfo ------------------------------ */
1531 : tVERSIONINFO loadmemopts fix_version tBEGIN ver_blocks tEND
{
1539 $$
->memopt
= WRC_MO_MOVEABLE |
(win32 ? WRC_MO_PURE
: 0);
1540 $$
->blocks
= get_ver_block_head
($5);
1541 /* Set language; there is no version or characteristics */
1542 $$
->lvc.language
= dup_language
(currentlanguage
);
1547 : /* Empty */ { $$
= new_versioninfo
(); }
1548 | fix_version tFILEVERSION expr
',' expr
',' expr
',' expr
{
1550 yyerror("FILEVERSION already defined");
1552 $$
->filever_maj1
= $3;
1553 $$
->filever_maj2
= $5;
1554 $$
->filever_min1
= $7;
1555 $$
->filever_min2
= $9;
1558 | fix_version tPRODUCTVERSION expr
',' expr
',' expr
',' expr
{
1560 yyerror("PRODUCTVERSION already defined");
1562 $$
->prodver_maj1
= $3;
1563 $$
->prodver_maj2
= $5;
1564 $$
->prodver_min1
= $7;
1565 $$
->prodver_min2
= $9;
1568 | fix_version tFILEFLAGS expr
{
1570 yyerror("FILEFLAGS already defined");
1575 | fix_version tFILEFLAGSMASK expr
{
1577 yyerror("FILEFLAGSMASK already defined");
1579 $$
->fileflagsmask
= $3;
1582 | fix_version tFILEOS expr
{
1584 yyerror("FILEOS already defined");
1589 | fix_version tFILETYPE expr
{
1591 yyerror("FILETYPE already defined");
1596 | fix_version tFILESUBTYPE expr
{
1598 yyerror("FILESUBTYPE already defined");
1600 $$
->filesubtype
= $3;
1606 : /* Empty */ { $$
= NULL
; }
1607 | ver_blocks ver_block
{
1616 : tBLOCK tSTRING tBEGIN ver_values tEND
{
1617 $$
= new_ver_block
();
1619 $$
->values
= get_ver_value_head
($4);
1624 : /* Empty */ { $$
= NULL
; }
1625 | ver_values ver_value
{
1635 $$
= new_ver_value
();
1636 $$
->type
= val_block
;
1637 $$
->value.block
= $1;
1639 | tVALUE tSTRING
',' tSTRING
{
1640 $$
= new_ver_value
();
1645 | tVALUE tSTRING
',' ver_words
{
1646 $$
= new_ver_value
();
1647 $$
->type
= val_words
;
1649 $$
->value.words
= $4;
1654 : expr
{ $$
= new_ver_words
($1); }
1655 | ver_words
',' expr
{ $$
= add_ver_words
($1, $3); }
1658 /* ------------------------------ Toolbar ------------------------------ */
1659 toolbar: tTOOLBAR loadmemopts expr
',' expr opt_lvc tBEGIN toolbar_items tEND
{
1661 toolbar_item_t
*items
= get_tlbr_buttons_head
($8, &nitems
);
1662 $$
= new_toolbar
($3, $5, items
, nitems
);
1670 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE
;
1677 if
(!$$
->lvc.language
)
1679 $$
->lvc.language
= dup_language
(currentlanguage
);
1685 : /* Empty */ { $$
= NULL
; }
1686 | toolbar_items tBUTTON expr
{
1687 toolbar_item_t
*idrec
= new_toolbar_item
();
1689 $$
= ins_tlbr_button
($1, idrec
);
1691 | toolbar_items tSEPARATOR
{
1692 toolbar_item_t
*idrec
= new_toolbar_item
();
1694 $$
= ins_tlbr_button
($1, idrec
);
1698 /* ------------------------------ Memory options ------------------------------ */
1700 : /* Empty */ { $$
= NULL
; }
1701 | loadmemopts lamo
{
1711 | loadmemopts lama
{
1720 *$2 &= WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE
;
1726 lamo
: tPRELOAD
{ $$
= new_int
(WRC_MO_PRELOAD
); }
1727 | tMOVEABLE
{ $$
= new_int
(WRC_MO_MOVEABLE
); }
1728 | tDISCARDABLE
{ $$
= new_int
(WRC_MO_DISCARDABLE
); }
1729 | tPURE
{ $$
= new_int
(WRC_MO_PURE
); }
1732 lama
: tLOADONCALL
{ $$
= new_int
(~WRC_MO_PRELOAD
); }
1733 | tFIXED
{ $$
= new_int
(~WRC_MO_MOVEABLE
); }
1734 | tIMPURE
{ $$
= new_int
(~WRC_MO_PURE
); }
1737 /* ------------------------------ Win32 options ------------------------------ */
1738 opt_lvc
: /* Empty */ { $$
= new_lvc
(); }
1739 | opt_lvc opt_language
{
1741 parser_warning
("LANGUAGE not supported in 16-bit mode\n");
1743 yyerror("Language already defined");
1747 | opt_lvc opt_characts
{
1749 parser_warning
("CHARACTERISTICS not supported in 16-bit mode\n");
1751 yyerror("Characteristics already defined");
1755 | opt_lvc opt_version
{
1757 parser_warning
("VERSION not supported in 16-bit mode\n");
1759 yyerror("Version already defined");
1766 * This here is another s/r conflict on {bi,u}nary + and -.
1767 * It is due to the look-ahead which must determine when the
1768 * rule opt_language ends. It could be solved with adding a
1769 * tNL at the end, but that seems unreasonable to do.
1770 * The conflict is now moved to the expression handling below.
1773 : tLANGUAGE expr
',' expr
{ $$
= new_language
($2, $4);
1774 if
(get_language_codepage
($2, $4) == -1)
1775 yyerror( "Language %04x is not supported", ($4<<10) + $2);
1780 : tCHARACTERISTICS expr
{ $$
= new_characts
($2); }
1784 : tVERSION expr
{ $$
= new_version
($2); }
1787 /* ------------------------------ Raw data handling ------------------------------ */
1788 raw_data: opt_lvc tBEGIN raw_elements tEND
{
1795 if
(!$3->lvc.language
)
1796 $3->lvc.language
= dup_language
(currentlanguage
);
1803 : tRAWDATA
{ $$
= $1; }
1804 | tNUMBER
{ $$
= int2raw_data
($1); }
1805 |
'-' tNUMBER
{ $$
= int2raw_data
(-($2)); }
1806 | tLNUMBER
{ $$
= long2raw_data
($1); }
1807 |
'-' tLNUMBER
{ $$
= long2raw_data
(-($2)); }
1808 | tSTRING
{ $$
= str2raw_data
($1); }
1809 | raw_elements opt_comma tRAWDATA
{ $$
= merge_raw_data
($1, $3); free
($3->data
); free
($3); }
1810 | raw_elements opt_comma tNUMBER
{ $$
= merge_raw_data_int
($1, $3); }
1811 | raw_elements opt_comma
'-' tNUMBER
{ $$
= merge_raw_data_int
($1, -($4)); }
1812 | raw_elements opt_comma tLNUMBER
{ $$
= merge_raw_data_long
($1, $3); }
1813 | raw_elements opt_comma
'-' tLNUMBER
{ $$
= merge_raw_data_long
($1, -($4)); }
1814 | raw_elements opt_comma tSTRING
{ $$
= merge_raw_data_str
($1, $3); }
1817 /* File data or raw data */
1818 file_raw: filename
{ $$
= load_file
($1,dup_language
(currentlanguage
)); }
1819 | raw_data
{ $$
= $1; }
1822 /* ------------------------------ Win32 expressions ------------------------------ */
1823 /* All win16 numbers are also handled here. This is inconsistent with MS'
1824 * resource compiler, but what the heck, its just handy to have.
1826 e_expr
: /* Empty */ { $$
= 0; }
1827 | expr
{ $$
= new_int
($1); }
1830 /* This rule moves ALL s/r conflicts on {bi,u}nary - and + to here */
1831 expr
: xpr
{ $$
= ($1); }
1834 xpr
: xpr
'+' xpr
{ $$
= ($1) + ($3); }
1835 | xpr
'-' xpr
{ $$
= ($1) - ($3); }
1836 | xpr
'|' xpr
{ $$
= ($1) |
($3); }
1837 | xpr
'&' xpr
{ $$
= ($1) & ($3); }
1838 | xpr
'*' xpr
{ $$
= ($1) * ($3); }
1839 | xpr
'/' xpr
{ $$
= ($1) / ($3); }
1840 | xpr
'^' xpr
{ $$
= ($1) ^
($3); }
1841 |
'~' xpr
{ $$
= ~
($2); }
1842 |
'-' xpr %prec pUPM
{ $$
= -($2); }
1843 |
'+' xpr %prec pUPM
{ $$
= $2; }
1844 |
'(' xpr
')' { $$
= $2; }
1845 | any_num
{ $$
= $1; }
1846 | tNOT any_num
{ $$
= ~
($2); }
1849 any_num
: tNUMBER
{ $$
= $1; }
1850 | tLNUMBER
{ $$
= $1; }
1854 /* Dialog specific functions */
1855 static dialog_t
*dialog_style
(style_t
* st
, dialog_t
*dlg
)
1857 assert
(dlg
!= NULL
);
1858 if
(dlg
->style
== NULL
)
1860 dlg
->style
= new_style
(0,0);
1865 parser_warning
("Style already defined, or-ing together\n");
1869 dlg
->style
->or_mask
= 0;
1870 dlg
->style
->and_mask
= 0;
1872 dlg
->style
->or_mask |
= st
->or_mask
;
1873 dlg
->style
->and_mask |
= st
->and_mask
;
1874 dlg
->gotstyle
= TRUE
;
1879 static dialog_t
*dialog_exstyle
(style_t
*st
, dialog_t
*dlg
)
1881 assert
(dlg
!= NULL
);
1882 if
(dlg
->exstyle
== NULL
)
1884 dlg
->exstyle
= new_style
(0,0);
1889 parser_warning
("ExStyle already defined, or-ing together\n");
1893 dlg
->exstyle
->or_mask
= 0;
1894 dlg
->exstyle
->and_mask
= 0;
1896 dlg
->exstyle
->or_mask |
= st
->or_mask
;
1897 dlg
->exstyle
->and_mask |
= st
->and_mask
;
1898 dlg
->gotexstyle
= TRUE
;
1903 static dialog_t
*dialog_caption
(string_t
*s
, dialog_t
*dlg
)
1905 assert
(dlg
!= NULL
);
1907 yyerror("Caption already defined");
1912 static dialog_t
*dialog_font
(font_id_t
*f
, dialog_t
*dlg
)
1914 assert
(dlg
!= NULL
);
1916 yyerror("Font already defined");
1921 static dialog_t
*dialog_class
(name_id_t
*n
, dialog_t
*dlg
)
1923 assert
(dlg
!= NULL
);
1925 yyerror("Class already defined");
1930 static dialog_t
*dialog_menu
(name_id_t
*m
, dialog_t
*dlg
)
1932 assert
(dlg
!= NULL
);
1934 yyerror("Menu already defined");
1939 static dialog_t
*dialog_language
(language_t
*l
, dialog_t
*dlg
)
1941 assert
(dlg
!= NULL
);
1942 if
(dlg
->lvc.language
)
1943 yyerror("Language already defined");
1944 dlg
->lvc.language
= l
;
1948 static dialog_t
*dialog_characteristics
(characts_t
*c
, dialog_t
*dlg
)
1950 assert
(dlg
!= NULL
);
1951 if
(dlg
->lvc.characts
)
1952 yyerror("Characteristics already defined");
1953 dlg
->lvc.characts
= c
;
1957 static dialog_t
*dialog_version
(version_t
*v
, dialog_t
*dlg
)
1959 assert
(dlg
!= NULL
);
1960 if
(dlg
->lvc.version
)
1961 yyerror("Version already defined");
1962 dlg
->lvc.version
= v
;
1966 /* Controls specific functions */
1967 static control_t
*ins_ctrl
(int type
, int special_style
, control_t
*ctrl
, control_t
*prev
)
1969 /* Hm... this seems to be jammed in at all time... */
1970 int defaultstyle
= WS_CHILD | WS_VISIBLE
;
1972 assert
(ctrl
!= NULL
);
1978 /* Check for duplicate identifiers */
1981 if
(ctrl
->id
!= -1 && ctrl
->id
== prev
->id
)
1982 parser_warning
("Duplicate dialog control id %d\n", ctrl
->id
);
1988 ctrl
->ctlclass
= new_name_id
();
1989 ctrl
->ctlclass
->type
= name_ord
;
1990 ctrl
->ctlclass
->name.i_name
= type
;
1996 if
(special_style
!= BS_GROUPBOX
&& special_style
!= BS_RADIOBUTTON
)
1997 defaultstyle |
= WS_TABSTOP
;
2000 defaultstyle |
= WS_TABSTOP | WS_BORDER
;
2003 defaultstyle |
= LBS_NOTIFY | WS_BORDER
;
2006 if
(!(ctrl
->style
->or_mask
& (CBS_SIMPLE | CBS_DROPDOWN | CBS_DROPDOWNLIST
)))
2007 defaultstyle |
= CBS_SIMPLE
;
2010 if
(special_style
== SS_CENTER || special_style
== SS_LEFT || special_style
== SS_RIGHT
)
2011 defaultstyle |
= WS_GROUP
;
2015 if
(!ctrl
->gotstyle
) /* Handle default style setting */
2020 defaultstyle |
= ES_LEFT
;
2023 defaultstyle |
= LBS_NOTIFY
;
2026 defaultstyle |
= CBS_SIMPLE | WS_TABSTOP
;
2029 defaultstyle |
= SBS_HORZ
;
2032 switch
(special_style
)
2035 case BS_DEFPUSHBUTTON
:
2037 /* case BS_PUSHBOX: */
2038 case BS_AUTORADIOBUTTON
:
2041 case BS_AUTOCHECKBOX
:
2042 defaultstyle |
= WS_TABSTOP
;
2045 parser_warning
("Unknown default button control-style 0x%08x\n", special_style
);
2047 case BS_RADIOBUTTON
:
2053 switch
(special_style
)
2058 defaultstyle |
= WS_GROUP
;
2060 case SS_ICON
: /* Special case */
2063 parser_warning
("Unknown default static control-style 0x%08x\n", special_style
);
2067 case
-1: /* Generic control */
2071 yyerror("Internal error (report this): Got weird control type 0x%08x", type
);
2075 /* The SS_ICON flag is always forced in for icon controls */
2076 if
(type
== CT_STATIC
&& special_style
== SS_ICON
)
2077 defaultstyle |
= SS_ICON
;
2079 if
(!ctrl
->gotstyle
)
2080 ctrl
->style
= new_style
(0,0);
2082 /* combine all styles */
2083 ctrl
->style
->or_mask
= ctrl
->style
->or_mask | defaultstyle | special_style
;
2084 ctrl
->gotstyle
= TRUE
;
2086 /* combine with NOT mask */
2089 ctrl
->style
->or_mask
&= ~
(ctrl
->style
->and_mask
);
2090 ctrl
->style
->and_mask
= 0;
2092 if
(ctrl
->gotexstyle
)
2094 ctrl
->exstyle
->or_mask
&= ~
(ctrl
->exstyle
->and_mask
);
2095 ctrl
->exstyle
->and_mask
= 0;
2100 static int get_class_idW
(const WCHAR
*cc
)
2102 static const WCHAR szBUTTON
[] = {'B','U','T','T','O','N',0};
2103 static const WCHAR szCOMBOBOX
[] = {'C','O','M','B','O','B','O','X',0};
2104 static const WCHAR szLISTBOX
[] = {'L','I','S','T','B','O','X',0};
2105 static const WCHAR szEDIT
[] = {'E','D','I','T',0};
2106 static const WCHAR szSTATIC
[] = {'S','T','A','T','I','C',0};
2107 static const WCHAR szSCROLLBAR
[] = {'S','C','R','O','L','L','B','A','R',0};
2109 if
(!strcmpiW
(szBUTTON
, cc
))
2111 if
(!strcmpiW
(szCOMBOBOX
, cc
))
2113 if
(!strcmpiW
(szLISTBOX
, cc
))
2115 if
(!strcmpiW
(szEDIT
, cc
))
2117 if
(!strcmpiW
(szSTATIC
, cc
))
2119 if
(!strcmpiW
(szSCROLLBAR
, cc
))
2120 return CT_SCROLLBAR
;
2125 static int get_class_idA
(const char *cc
)
2127 if
(!strcasecmp
("BUTTON", cc
))
2129 if
(!strcasecmp
("COMBOBOX", cc
))
2131 if
(!strcasecmp
("LISTBOX", cc
))
2133 if
(!strcasecmp
("EDIT", cc
))
2135 if
(!strcasecmp
("STATIC", cc
))
2137 if
(!strcasecmp
("SCROLLBAR", cc
))
2138 return CT_SCROLLBAR
;
2144 static name_id_t
*convert_ctlclass
(name_id_t
*cls
)
2148 if
(cls
->type
== name_ord
)
2150 assert
(cls
->type
== name_str
);
2151 if
(cls
->name.s_name
->type
== str_unicode
)
2152 iclass
= get_class_idW
(cls
->name.s_name
->str.wstr
);
2154 iclass
= get_class_idA
(cls
->name.s_name
->str.cstr
);
2157 return cls
; /* No default, return user controlclass */
2159 free
(cls
->name.s_name
->str.cstr
);
2160 free
(cls
->name.s_name
);
2161 cls
->type
= name_ord
;
2162 cls
->name.i_name
= iclass
;
2166 /* DialogEx specific functions */
2167 static dialogex_t
*dialogex_style
(style_t
* st
, dialogex_t
*dlg
)
2169 assert
(dlg
!= NULL
);
2170 if
(dlg
->style
== NULL
)
2172 dlg
->style
= new_style
(0,0);
2177 parser_warning
("Style already defined, or-ing together\n");
2181 dlg
->style
->or_mask
= 0;
2182 dlg
->style
->and_mask
= 0;
2184 dlg
->style
->or_mask |
= st
->or_mask
;
2185 dlg
->style
->and_mask |
= st
->and_mask
;
2186 dlg
->gotstyle
= TRUE
;
2191 static dialogex_t
*dialogex_exstyle
(style_t
* st
, dialogex_t
*dlg
)
2193 assert
(dlg
!= NULL
);
2194 if
(dlg
->exstyle
== NULL
)
2196 dlg
->exstyle
= new_style
(0,0);
2201 parser_warning
("ExStyle already defined, or-ing together\n");
2205 dlg
->exstyle
->or_mask
= 0;
2206 dlg
->exstyle
->and_mask
= 0;
2208 dlg
->exstyle
->or_mask |
= st
->or_mask
;
2209 dlg
->exstyle
->and_mask |
= st
->and_mask
;
2210 dlg
->gotexstyle
= TRUE
;
2215 static dialogex_t
*dialogex_caption
(string_t
*s
, dialogex_t
*dlg
)
2217 assert
(dlg
!= NULL
);
2219 yyerror("Caption already defined");
2224 static dialogex_t
*dialogex_font
(font_id_t
*f
, dialogex_t
*dlg
)
2226 assert
(dlg
!= NULL
);
2228 yyerror("Font already defined");
2233 static dialogex_t
*dialogex_class
(name_id_t
*n
, dialogex_t
*dlg
)
2235 assert
(dlg
!= NULL
);
2237 yyerror("Class already defined");
2242 static dialogex_t
*dialogex_menu
(name_id_t
*m
, dialogex_t
*dlg
)
2244 assert
(dlg
!= NULL
);
2246 yyerror("Menu already defined");
2251 static dialogex_t
*dialogex_language
(language_t
*l
, dialogex_t
*dlg
)
2253 assert
(dlg
!= NULL
);
2254 if
(dlg
->lvc.language
)
2255 yyerror("Language already defined");
2256 dlg
->lvc.language
= l
;
2260 static dialogex_t
*dialogex_characteristics
(characts_t
*c
, dialogex_t
*dlg
)
2262 assert
(dlg
!= NULL
);
2263 if
(dlg
->lvc.characts
)
2264 yyerror("Characteristics already defined");
2265 dlg
->lvc.characts
= c
;
2269 static dialogex_t
*dialogex_version
(version_t
*v
, dialogex_t
*dlg
)
2271 assert
(dlg
!= NULL
);
2272 if
(dlg
->lvc.version
)
2273 yyerror("Version already defined");
2274 dlg
->lvc.version
= v
;
2278 /* Accelerator specific functions */
2279 static event_t
*add_event
(int key
, int id
, int flags
, event_t
*prev
)
2281 event_t
*ev
= new_event
();
2283 if
((flags
& (WRC_AF_VIRTKEY | WRC_AF_ASCII
)) == (WRC_AF_VIRTKEY | WRC_AF_ASCII
))
2284 yyerror("Cannot use both ASCII and VIRTKEY");
2288 ev
->flags
= flags
& ~WRC_AF_ASCII
;
2295 static event_t
*add_string_event
(string_t
*key
, int id
, int flags
, event_t
*prev
)
2298 event_t
*ev
= new_event
();
2300 if
(key
->type
== str_char
)
2302 if
((flags
& WRC_AF_VIRTKEY
) && (!isupper
(key
->str.cstr
[0] & 0xff) && !isdigit
(key
->str.cstr
[0] & 0xff)))
2303 yyerror("VIRTKEY code is not equal to ascii value");
2305 if
(key
->str.cstr
[0] == '^' && (flags
& WRC_AF_CONTROL
) != 0)
2307 yyerror("Cannot use both '^' and CONTROL modifier");
2309 else if
(key
->str.cstr
[0] == '^')
2311 keycode
= toupper
(key
->str.cstr
[1]) - '@';
2313 yyerror("Control-code out of range");
2316 keycode
= key
->str.cstr
[0];
2320 if
((flags
& WRC_AF_VIRTKEY
) && !isupperW
(key
->str.wstr
[0]) && !isdigitW
(key
->str.wstr
[0]))
2321 yyerror("VIRTKEY code is not equal to ascii value");
2323 if
(key
->str.wstr
[0] == '^' && (flags
& WRC_AF_CONTROL
) != 0)
2325 yyerror("Cannot use both '^' and CONTROL modifier");
2327 else if
(key
->str.wstr
[0] == '^')
2329 keycode
= toupperW
(key
->str.wstr
[1]) - '@';
2331 yyerror("Control-code out of range");
2334 keycode
= key
->str.wstr
[0];
2339 ev
->flags
= flags
& ~WRC_AF_ASCII
;
2346 /* MenuEx specific functions */
2347 static itemex_opt_t
*new_itemex_opt
(int id
, int type
, int state
, int helpid
)
2349 itemex_opt_t
*opt
= xmalloc
(sizeof
(itemex_opt_t
));
2350 memset
( opt
, 0, sizeof
(*opt
) );
2354 opt
->helpid
= helpid
;
2358 /* Raw data functions */
2359 static raw_data_t
*load_file
(string_t
*filename
, language_t
*lang
)
2365 int codepage
= get_language_codepage
(lang
->id
, lang
->sub
);
2367 /* FIXME: we may want to use utf-8 here */
2368 if
(codepage
<= 0 && filename
->type
!= str_char
)
2369 yyerror("Cannot convert filename to ASCII string");
2370 name
= convert_string
( filename
, str_char
, codepage
);
2371 if
(!(path
= wpp_find_include
(name
->str.cstr
, input_name
)))
2372 yyerror("Cannot open file %s", name
->str.cstr
);
2373 if
(!(fp
= fopen
( path
, "rb" )))
2374 yyerror("Cannot open file %s", name
->str.cstr
);
2376 rd
= new_raw_data
();
2377 fseek
(fp
, 0, SEEK_END
);
2378 rd
->size
= ftell
(fp
);
2379 fseek
(fp
, 0, SEEK_SET
);
2382 rd
->data
= xmalloc
(rd
->size
);
2383 fread
(rd
->data
, rd
->size
, 1, fp
);
2385 else rd
->data
= NULL
;
2387 rd
->lvc.language
= lang
;
2392 static raw_data_t
*int2raw_data
(int i
)
2396 if
( ( i
>= 0 && (int)((unsigned short)i
) != i
) ||
2397 ( i
< 0 && (int)((short)i
) != i
) )
2398 parser_warning
("Integer constant out of 16bit range (%d), truncated to %d\n", i
, (short)i
);
2400 rd
= new_raw_data
();
2401 rd
->size
= sizeof
(short);
2402 rd
->data
= xmalloc
(rd
->size
);
2405 #ifdef WORDS_BIGENDIAN
2409 rd
->data
[0] = HIBYTE
(i
);
2410 rd
->data
[1] = LOBYTE
(i
);
2413 #ifndef WORDS_BIGENDIAN
2417 rd
->data
[1] = HIBYTE
(i
);
2418 rd
->data
[0] = LOBYTE
(i
);
2424 static raw_data_t
*long2raw_data
(int i
)
2427 rd
= new_raw_data
();
2428 rd
->size
= sizeof
(int);
2429 rd
->data
= xmalloc
(rd
->size
);
2432 #ifdef WORDS_BIGENDIAN
2436 rd
->data
[0] = HIBYTE
(HIWORD
(i
));
2437 rd
->data
[1] = LOBYTE
(HIWORD
(i
));
2438 rd
->data
[2] = HIBYTE
(LOWORD
(i
));
2439 rd
->data
[3] = LOBYTE
(LOWORD
(i
));
2442 #ifndef WORDS_BIGENDIAN
2446 rd
->data
[3] = HIBYTE
(HIWORD
(i
));
2447 rd
->data
[2] = LOBYTE
(HIWORD
(i
));
2448 rd
->data
[1] = HIBYTE
(LOWORD
(i
));
2449 rd
->data
[0] = LOBYTE
(LOWORD
(i
));
2455 static raw_data_t
*str2raw_data
(string_t
*str
)
2458 rd
= new_raw_data
();
2459 rd
->size
= str
->size
* (str
->type
== str_char ?
1 : 2);
2460 rd
->data
= xmalloc
(rd
->size
);
2461 if
(str
->type
== str_char
)
2462 memcpy
(rd
->data
, str
->str.cstr
, rd
->size
);
2463 else if
(str
->type
== str_unicode
)
2468 #ifdef WORDS_BIGENDIAN
2472 for
(i
= 0; i
< str
->size
; i
++)
2474 rd
->data
[2*i
+ 0] = HIBYTE
((WORD
)str
->str.wstr
[i
]);
2475 rd
->data
[2*i
+ 1] = LOBYTE
((WORD
)str
->str.wstr
[i
]);
2478 #ifndef WORDS_BIGENDIAN
2482 for
(i
= 0; i
< str
->size
; i
++)
2484 rd
->data
[2*i
+ 1] = HIBYTE
((WORD
)str
->str.wstr
[i
]);
2485 rd
->data
[2*i
+ 0] = LOBYTE
((WORD
)str
->str.wstr
[i
]);
2491 internal_error
(__FILE__
, __LINE__
, "Invalid stringtype\n");
2495 static raw_data_t
*merge_raw_data
(raw_data_t
*r1
, raw_data_t
*r2
)
2497 r1
->data
= xrealloc
(r1
->data
, r1
->size
+ r2
->size
);
2498 memcpy
(r1
->data
+ r1
->size
, r2
->data
, r2
->size
);
2499 r1
->size
+= r2
->size
;
2503 static raw_data_t
*merge_raw_data_int
(raw_data_t
*r1
, int i
)
2505 raw_data_t
*t
= int2raw_data
(i
);
2506 merge_raw_data
(r1
, t
);
2512 static raw_data_t
*merge_raw_data_long
(raw_data_t
*r1
, int i
)
2514 raw_data_t
*t
= long2raw_data
(i
);
2515 merge_raw_data
(r1
, t
);
2521 static raw_data_t
*merge_raw_data_str
(raw_data_t
*r1
, string_t
*str
)
2523 raw_data_t
*t
= str2raw_data
(str
);
2524 merge_raw_data
(r1
, t
);
2530 /* Function the go back in a list to get the head */
2531 static menu_item_t
*get_item_head
(menu_item_t
*p
)
2540 static menuex_item_t
*get_itemex_head
(menuex_item_t
*p
)
2549 static resource_t
*get_resource_head
(resource_t
*p
)
2558 static ver_block_t
*get_ver_block_head
(ver_block_t
*p
)
2567 static ver_value_t
*get_ver_value_head
(ver_value_t
*p
)
2576 static control_t
*get_control_head
(control_t
*p
)
2585 static event_t
*get_event_head
(event_t
*p
)
2594 /* Find a stringtable with given language */
2595 static stringtable_t
*find_stringtable
(lvc_t
*lvc
)
2599 assert
(lvc
!= NULL
);
2602 lvc
->language
= dup_language
(currentlanguage
);
2604 for
(stt
= sttres
; stt
; stt
= stt
->next
)
2606 if
(stt
->lvc.language
->id
== lvc
->language
->id
2607 && stt
->lvc.language
->sub
== lvc
->language
->sub
)
2609 /* Found a table with the same language */
2610 /* The version and characteristics are now handled
2611 * in the generation of the individual stringtables.
2612 * This enables localized analysis.
2613 if((stt->lvc.version && lvc->version && *(stt->lvc.version) != *(lvc->version))
2614 || (!stt->lvc.version && lvc->version)
2615 || (stt->lvc.version && !lvc->version))
2616 parser_warning("Stringtable's versions are not the same, using first definition\n");
2618 if((stt->lvc.characts && lvc->characts && *(stt->lvc.characts) != *(lvc->characts))
2619 || (!stt->lvc.characts && lvc->characts)
2620 || (stt->lvc.characts && !lvc->characts))
2621 parser_warning("Stringtable's characteristics are not the same, using first definition\n");
2629 /* qsort sorting function for string table entries */
2630 #define STE(p) ((const stt_entry_t *)(p))
2631 static int sort_stt_entry
(const void *e1
, const void *e2
)
2633 return STE
(e1
)->id
- STE
(e2
)->id
;
2637 static resource_t
*build_stt_resources
(stringtable_t
*stthead
)
2640 stringtable_t
*newstt
;
2642 resource_t
*rsclist
= NULL
;
2643 resource_t
*rsctail
= NULL
;
2648 characts_t
*characts
;
2654 /* For all languages defined */
2655 for
(stt
= stthead
; stt
; stt
= stt
->next
)
2657 assert
(stt
->nentries
> 0);
2659 /* Sort the entries */
2660 if
(stt
->nentries
> 1)
2661 qsort
(stt
->entries
, stt
->nentries
, sizeof
(stt
->entries
[0]), sort_stt_entry
);
2663 for
(i
= 0; i
< stt
->nentries
; )
2665 newstt
= new_stringtable
(&stt
->lvc
);
2666 newstt
->entries
= xmalloc
(16 * sizeof
(stt_entry_t
));
2667 memset
( newstt
->entries
, 0, 16 * sizeof
(stt_entry_t
) );
2668 newstt
->nentries
= 16;
2669 newstt
->idbase
= stt
->entries
[i
].id
& ~
0xf;
2670 for
(j
= 0; j
< 16 && i
< stt
->nentries
; j
++)
2672 if
(stt
->entries
[i
].id
- newstt
->idbase
== j
)
2674 newstt
->entries
[j
] = stt
->entries
[i
];
2682 /* Check individual memory options and get
2683 * the first characteristics/version
2685 for
(j
= 0; j
< 16; j
++)
2687 if
(!newstt
->entries
[j
].str
)
2689 andsum
&= newstt
->entries
[j
].memopt
;
2690 orsum |
= newstt
->entries
[j
].memopt
;
2692 characts
= newstt
->entries
[j
].characts
;
2694 version
= newstt
->entries
[j
].version
;
2698 warning
("Stringtable's memory options are not equal (idbase: %d)\n", newstt
->idbase
);
2700 /* Check version and characteristics */
2701 for
(j
= 0; j
< 16; j
++)
2704 && newstt
->entries
[j
].characts
2705 && *newstt
->entries
[j
].characts
!= *characts
)
2706 warning
("Stringtable's characteristics are not the same (idbase: %d)\n", newstt
->idbase
);
2708 && newstt
->entries
[j
].version
2709 && *newstt
->entries
[j
].version
!= *version
)
2710 warning
("Stringtable's versions are not the same (idbase: %d)\n", newstt
->idbase
);
2712 rsc
= new_resource
(res_stt
, newstt
, newstt
->memopt
, newstt
->lvc.language
);
2713 rsc
->name
= new_name_id
();
2714 rsc
->name
->type
= name_ord
;
2715 rsc
->name
->name.i_name
= (newstt
->idbase
>> 4) + 1;
2716 rsc
->memopt
= andsum
; /* Set to least common denominator */
2717 newstt
->memopt
= andsum
;
2718 newstt
->lvc.characts
= characts
;
2719 newstt
->lvc.version
= version
;
2727 rsctail
->next
= rsc
;
2728 rsc
->prev
= rsctail
;
2737 static toolbar_item_t
*ins_tlbr_button
(toolbar_item_t
*prev
, toolbar_item_t
*idrec
)
2746 static toolbar_item_t
*get_tlbr_buttons_head
(toolbar_item_t
*p
, int *nitems
)
2765 static string_t
*make_filename
(string_t
*str
)
2767 if
(str
->type
== str_char
)
2771 /* Remove escaped backslash and convert to forward */
2772 for
(cptr
= str
->str.cstr
; (cptr
= strchr
(cptr
, '\\')) != NULL
; cptr
++)
2776 memmove
(cptr
, cptr
+1, strlen
(cptr
));
2786 /* Remove escaped backslash and convert to forward */
2787 for
(wptr
= str
->str.wstr
; (wptr
= strchrW
(wptr
, '\\')) != NULL
; wptr
++)
2791 memmove
(wptr
, wptr
+1, strlenW
(wptr
));
2801 * Process all resources to extract fonts and build
2802 * a fontdir resource.
2804 * Note: MS' resource compiler (build 1472) does not
2805 * handle font resources with different languages.
2806 * The fontdir is generated in the last active language
2807 * and font identifiers must be unique across the entire
2809 * This is not logical considering the localization
2810 * constraints of all other resource types. MS has,
2811 * most probably, never testet localized fonts. However,
2812 * using fontresources is rare, so it might not occur
2813 * in normal applications.
2814 * Wine does require better localization because a lot
2815 * of languages are coded into the same executable.
2816 * Therefore, I will generate fontdirs for *each*
2817 * localized set of fonts.
2819 static resource_t
*build_fontdir
(resource_t
**fnt
, int nfnt
)
2821 static int once
= 0;
2824 warning
("Need to parse fonts, not yet implemented (fnt: %p, nfnt: %d)\n", fnt
, nfnt
);
2830 static resource_t
*build_fontdirs
(resource_t
*tail
)
2833 resource_t
*lst
= NULL
;
2834 resource_t
**fnt
= NULL
; /* List of all fonts */
2836 resource_t
**fnd
= NULL
; /* List of all fontdirs */
2838 resource_t
**lanfnt
= NULL
;
2845 nid.type
= name_str
;
2846 nid.name.s_name
= &str
;
2847 str.type
= str_char
;
2848 str.str.cstr
= xstrdup
("FONTDIR");
2851 /* Extract all fonts and fontdirs */
2852 for
(rsc
= tail
; rsc
; rsc
= rsc
->prev
)
2854 if
(rsc
->type
== res_fnt
)
2857 fnt
= xrealloc
(fnt
, nfnt
* sizeof
(*fnt
));
2860 else if
(rsc
->type
== res_fntdir
)
2863 fnd
= xrealloc
(fnd
, nfnd
* sizeof
(*fnd
));
2868 /* Verify the name of the present fontdirs */
2869 for
(i
= 0; i
< nfnd
; i
++)
2871 if
(compare_name_id
(&nid
, fnd
[i
]->name
))
2873 warning
("User supplied FONTDIR entry has an invalid name '%s', ignored\n",
2874 get_nameid_str
(fnd
[i
]->name
));
2883 warning
("Found %d FONTDIR entries without any fonts present\n", nfnd
);
2888 lanfnt
= xmalloc
(nfnt
* sizeof
(*lanfnt
));
2889 memset
( lanfnt
, 0, nfnt
* sizeof
(*lanfnt
));
2891 /* Get all fonts covered by fontdirs */
2892 for
(i
= 0; i
< nfnd
; i
++)
2900 for
(j
= 0; j
< nfnt
; j
++)
2904 if
(fnt
[j
]->lan
->id
== fnd
[i
]->lan
->id
&& fnt
[j
]->lan
->sub
== fnd
[i
]->lan
->sub
)
2906 lanfnt
[nlanfnt
] = fnt
[j
];
2912 cnt
= *(WORD
*)fnd
[i
]->res.fnd
->data
->data
;
2915 else if
(nlanfnt
== BYTESWAP_WORD
(cnt
))
2918 error("FONTDIR for language %d,%d has wrong count (%d, expected %d)\n",
2919 fnd
[i
]->lan
->id
, fnd
[i
]->lan
->sub
, cnt
, nlanfnt
);
2920 #ifdef WORDS_BIGENDIAN
2921 if
((byteorder
== WRC_BO_LITTLE
&& !isswapped
) ||
(byteorder
!= WRC_BO_LITTLE
&& isswapped
))
2923 if
((byteorder
== WRC_BO_BIG
&& !isswapped
) ||
(byteorder
!= WRC_BO_BIG
&& isswapped
))
2926 internal_error
(__FILE__
, __LINE__
, "User supplied FONTDIR needs byteswapping\n");
2930 /* We now have fonts left where we need to make a fontdir resource */
2931 for
(i
= fntleft
= 0; i
< nfnt
; i
++)
2938 /* Get fonts of same language in lanfnt[] */
2939 for
(i
= nlanfnt
= 0; i
< nfnt
; i
++)
2946 lanfnt
[nlanfnt
] = fnt
[i
];
2951 else if
(fnt
[i
]->lan
->id
== lanfnt
[0]->lan
->id
&& fnt
[i
]->lan
->sub
== lanfnt
[0]->lan
->sub
)
2955 /* and build a fontdir */
2956 rsc
= build_fontdir
(lanfnt
, nlanfnt
);
2977 * This gets invoked to determine whether the next resource
2978 * is to be of a standard-type (e.g. bitmaps etc.), or should
2979 * be a user-type resource. This function is required because
2980 * there is the _possibility_ of a lookahead token in the
2981 * parser, which is generated from the "expr" state in the
2984 * The general resource format is:
2985 * <identifier> <type> <flags> <resourcebody>
2987 * The <identifier> can either be tIDENT or "expr". The latter
2988 * will always generate a lookahead, which is the <type> of the
2989 * resource to parse. Otherwise, we need to get a new token from
2990 * the scanner to determine the next step.
2992 * The problem arrises when <type> is numerical. This case should
2993 * map onto default resource-types and be parsed as such instead
2994 * of being mapped onto user-type resources.
2996 * The trick lies in the fact that yacc (bison) doesn't care about
2997 * intermediate changes of the lookahead while reducing a rule. We
2998 * simply replace the lookahead with a token that will result in
2999 * a shift to the appropriate rule for the specific resource-type.
3001 static int rsrcid_to_token
(int lookahead
)
3004 const char *type
= "?";
3006 /* Get a token if we don't have one yet */
3007 if
(lookahead
== YYEMPTY
)
3010 /* Only numbers are possibly interesting */
3040 case WRC_RT_FONTDIR
:
3048 case WRC_RT_MESSAGETABLE
:
3049 type
= "MESSAGETABLE";
3050 token
= tMESSAGETABLE
;
3052 case WRC_RT_DLGINIT
:
3056 case WRC_RT_ACCELERATOR
:
3057 type
= "ACCELERATOR";
3058 token
= tACCELERATORS
;
3068 case WRC_RT_VERSION
:
3070 token
= tVERSIONINFO
;
3072 case WRC_RT_TOOLBAR
:
3082 type
= "STRINGTABLE";
3085 case WRC_RT_ANICURSOR
:
3086 case WRC_RT_ANIICON
:
3087 case WRC_RT_GROUP_CURSOR
:
3088 case WRC_RT_GROUP_ICON
:
3089 parser_warning
("Usertype uses reserved type ID %d, which is auto-generated\n", yylval.num
);
3092 case WRC_RT_DLGINCLUDE
:
3093 case WRC_RT_PLUGPLAY
:
3095 parser_warning
("Usertype uses reserved type ID %d, which is not supported by wrc yet\n", yylval.num
);