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"
138 #include "newstruc.h"
140 #include "wine/wpp.h"
141 #include "wine/unicode.h"
149 /* Berkeley yacc (byacc) doesn't seem to know about these */
150 /* Some *BSD supplied versions do define these though */
152 # define YYEMPTY (-1) /* Empty lookahead value of yychar */
155 # define YYLEX yylex()
158 #elif defined(YYBISON)
159 /* Bison was used for original development */
160 /* #define YYEMPTY -2 */
161 /* #define YYLEX yylex() */
164 /* No yacc we know yet */
165 # if !defined(YYEMPTY) || !defined(YYLEX)
166 # error Yacc version/type unknown. This version needs to be verified for settings of YYEMPTY and YYLEX.
167 # elif defined(__GNUC__) /* gcc defines the #warning directive */
168 # warning Yacc version/type unknown. It defines YYEMPTY and YYLEX, but is not tested
169 /* #else we just take a chance that it works... */
173 int want_nl
= 0; /* Signal flex that we need the next newline */
174 int want_id
= 0; /* Signal flex that we need the next identifier */
175 stringtable_t
*tagstt
; /* Stringtable tag.
176 * It is set while parsing a stringtable to one of
177 * the stringtables in the sttres list or a new one
178 * if the language was not parsed before.
180 stringtable_t
*sttres
; /* Stringtable resources. This holds the list of
181 * stringtables with different lanuages
183 static int dont_want_id
= 0; /* See language parsing for details */
185 /* Set to the current options of the currently scanning stringtable */
186 static int *tagstt_memopt
;
187 static characts_t
*tagstt_characts
;
188 static version_t
*tagstt_version
;
190 static const char riff
[4] = "RIFF"; /* RIFF file magic for animated cursor/icon */
192 /* Prototypes of here defined functions */
193 static event_t
*get_event_head
(event_t
*p
);
194 static control_t
*get_control_head
(control_t
*p
);
195 static ver_value_t
*get_ver_value_head
(ver_value_t
*p
);
196 static ver_block_t
*get_ver_block_head
(ver_block_t
*p
);
197 static resource_t
*get_resource_head
(resource_t
*p
);
198 static menuex_item_t
*get_itemex_head
(menuex_item_t
*p
);
199 static menu_item_t
*get_item_head
(menu_item_t
*p
);
200 static raw_data_t
*merge_raw_data_str
(raw_data_t
*r1
, string_t
*str
);
201 static raw_data_t
*merge_raw_data_int
(raw_data_t
*r1
, int i
);
202 static raw_data_t
*merge_raw_data_long
(raw_data_t
*r1
, int i
);
203 static raw_data_t
*merge_raw_data
(raw_data_t
*r1
, raw_data_t
*r2
);
204 static raw_data_t
*str2raw_data
(string_t
*str
);
205 static raw_data_t
*int2raw_data
(int i
);
206 static raw_data_t
*long2raw_data
(int i
);
207 static raw_data_t
*load_file
(string_t
*name
, language_t
*lang
);
208 static itemex_opt_t
*new_itemex_opt
(int id
, int type
, int state
, int helpid
);
209 static event_t
*add_string_event
(string_t
*key
, int id
, int flags
, event_t
*prev
);
210 static event_t
*add_event
(int key
, int id
, int flags
, event_t
*prev
);
211 static dialogex_t
*dialogex_version
(version_t
*v
, dialogex_t
*dlg
);
212 static dialogex_t
*dialogex_characteristics
(characts_t
*c
, dialogex_t
*dlg
);
213 static dialogex_t
*dialogex_language
(language_t
*l
, dialogex_t
*dlg
);
214 static dialogex_t
*dialogex_menu
(name_id_t
*m
, dialogex_t
*dlg
);
215 static dialogex_t
*dialogex_class
(name_id_t
*n
, dialogex_t
*dlg
);
216 static dialogex_t
*dialogex_font
(font_id_t
*f
, dialogex_t
*dlg
);
217 static dialogex_t
*dialogex_caption
(string_t
*s
, dialogex_t
*dlg
);
218 static dialogex_t
*dialogex_exstyle
(style_t
*st
, dialogex_t
*dlg
);
219 static dialogex_t
*dialogex_style
(style_t
*st
, dialogex_t
*dlg
);
220 static name_id_t
*convert_ctlclass
(name_id_t
*cls
);
221 static control_t
*ins_ctrl
(int type
, int special_style
, control_t
*ctrl
, control_t
*prev
);
222 static dialog_t
*dialog_version
(version_t
*v
, dialog_t
*dlg
);
223 static dialog_t
*dialog_characteristics
(characts_t
*c
, dialog_t
*dlg
);
224 static dialog_t
*dialog_language
(language_t
*l
, dialog_t
*dlg
);
225 static dialog_t
*dialog_menu
(name_id_t
*m
, dialog_t
*dlg
);
226 static dialog_t
*dialog_class
(name_id_t
*n
, dialog_t
*dlg
);
227 static dialog_t
*dialog_font
(font_id_t
*f
, dialog_t
*dlg
);
228 static dialog_t
*dialog_caption
(string_t
*s
, dialog_t
*dlg
);
229 static dialog_t
*dialog_exstyle
(style_t
* st
, dialog_t
*dlg
);
230 static dialog_t
*dialog_style
(style_t
* st
, dialog_t
*dlg
);
231 static resource_t
*build_stt_resources
(stringtable_t
*stthead
);
232 static stringtable_t
*find_stringtable
(lvc_t
*lvc
);
233 static toolbar_item_t
*ins_tlbr_button
(toolbar_item_t
*prev
, toolbar_item_t
*idrec
);
234 static toolbar_item_t
*get_tlbr_buttons_head
(toolbar_item_t
*p
, int *nitems
);
235 static string_t
*make_filename
(string_t
*s
);
236 static resource_t
*build_fontdirs
(resource_t
*tail
);
237 static resource_t
*build_fontdir
(resource_t
**fnt
, int nfnt
);
238 static int rsrcid_to_token
(int lookahead
);
270 menuex_item_t
*menexitm
;
278 toolbar_item_t
*tlbarItems
;
280 style_pair_t
*styles
;
286 %token
<num
> tNUMBER tLNUMBER
287 %token
<str
> tSTRING tIDENT tFILENAME
288 %token
<raw
> tRAWDATA
289 %token tACCELERATORS tBITMAP tCURSOR tDIALOG tDIALOGEX tMENU tMENUEX tMESSAGETABLE
290 %token tRCDATA tVERSIONINFO tSTRINGTABLE tFONT tFONTDIR tICON tHTML
291 %token tAUTO3STATE tAUTOCHECKBOX tAUTORADIOBUTTON tCHECKBOX tDEFPUSHBUTTON
292 %token tPUSHBUTTON tRADIOBUTTON tSTATE3
/* PUSHBOX */
293 %token tGROUPBOX tCOMBOBOX tLISTBOX tSCROLLBAR
294 %token tCONTROL tEDITTEXT
295 %token tRTEXT tCTEXT tLTEXT
297 %token tSHIFT tALT tASCII tVIRTKEY tGRAYED tCHECKED tINACTIVE tNOINVERT
298 %token tPURE tIMPURE tDISCARDABLE tLOADONCALL tPRELOAD tFIXED tMOVEABLE
299 %token tCLASS tCAPTION tCHARACTERISTICS tEXSTYLE tSTYLE tVERSION tLANGUAGE
300 %token tFILEVERSION tPRODUCTVERSION tFILEFLAGSMASK tFILEOS tFILETYPE tFILEFLAGS tFILESUBTYPE
301 %token tMENUBARBREAK tMENUBREAK tMENUITEM tPOPUP tSEPARATOR
303 %token tTOOLBAR tBUTTON
314 %type
<res
> resource_file resource resources resource_definition
315 %type
<stt
> stringtable strings
318 %type
<acc
> accelerators
321 %type
<ani
> cursor icon
322 %type
<dlg
> dialog dlg_attributes
323 %type
<ctl
> ctrls gen_ctrl lab_ctrl ctrl_desc iconinfo
325 %type
<dlgex
> dialogex dlgex_attribs
326 %type
<ctl
> exctrls gen_exctrl lab_exctrl exctrl_desc
329 %type
<raw
> raw_data raw_elements opt_data file_raw
330 %type
<veri
> versioninfo fix_version
331 %type
<verw
> ver_words
332 %type
<blk
> ver_blocks ver_block
333 %type
<val
> ver_values ver_value
335 %type
<menitm
> item_definitions menu_body
337 %type
<menexitm
> itemex_definitions menuex_body
338 %type
<exopt
> itemex_p_options itemex_options
339 %type
<msg
> messagetable
341 %type
<num
> item_options
342 %type
<nid
> nameid nameid_s ctlclass usertype
343 %type
<num
> acc_opt acc accs
344 %type
<iptr
> loadmemopts lamo lama
345 %type
<fntid
> opt_font opt_exfont opt_expr
347 %type
<lan
> opt_language
348 %type
<chars
> opt_characts
349 %type
<ver
> opt_version
352 %type
<tlbar
> toolbar
353 %type
<tlbarItems
> toolbar_items
354 %type
<dginit
> dlginit
355 %type
<styles
> optional_style_pair
365 /* First add stringtables to the resource-list */
366 rsc
= build_stt_resources
(sttres
);
367 /* 'build_stt_resources' returns a head and $1 is a tail */
376 /* Find the tail again */
377 while
($1 && $1->next
)
379 /* Now add any fontdirecory */
380 rsc
= build_fontdirs
($1);
381 /* 'build_fontdir' returns a head and $1 is a tail */
390 /* Final statement before were done */
391 resource_top
= get_resource_head
($1);
395 /* Resources are put into a linked list */
397 : /* Empty */ { $$
= NULL
; want_id
= 1; }
398 | resources resource
{
401 resource_t
*tail
= $2;
402 resource_t
*head
= $2;
411 /* Check for duplicate identifiers */
414 resource_t
*rsc
= $1;
417 if
(rsc
->type
== head
->type
418 && rsc
->lan
->id
== head
->lan
->id
419 && rsc
->lan
->sub
== head
->lan
->sub
420 && !compare_name_id
(rsc
->name
, head
->name
)
421 && (rsc
->type
!= res_usr ||
!compare_name_id
(rsc
->res.usr
->type
,head
->res.usr
->type
)))
423 yyerror("Duplicate resource name '%s'", get_nameid_str
(rsc
->name
));
432 resource_t
*tail
= $1;
440 if
(!dont_want_id
) /* See comments in language parsing below */
445 * The following newline rule will never get reduced because we never
446 * get the tNL token, unless we explicitly set the 'want_nl'
447 * flag, which we don't.
448 * The *ONLY* reason for this to be here is because Berkeley
449 * yacc (byacc), at least version 1.9, has a bug.
450 * (identified in the generated parser on the second
452 * static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93";
454 * This extra rule fixes it.
455 * The problem is that the expression handling rule "expr: xpr"
456 * is not reduced on non-terminal tokens, defined above in the
457 * %token declarations. Token tNL is the only non-terminal that
458 * can occur. The error becomes visible in the language parsing
459 * rule below, which looks at the look-ahead token and tests it
460 * for tNL. However, byacc already generates an error upon reading
461 * the token instead of keeping it as a lookahead. The reason
462 * lies in the lack of a $default transition in the "expr : xpr . "
463 * state (currently state 25). It is probably omitted because tNL
464 * is a non-terminal and the state contains 2 s/r conflicts. The
465 * state enumerates all possible transitions instead of using a
466 * $default transition.
467 * All in all, it is a bug in byacc. (period)
473 /* Parse top level resource definitions etc. */
475 : expr usrcvt resource_definition
{
479 if
($1 > 65535 ||
$1 < -32768)
480 yyerror("Resource's ID out of range (%d)", $1);
481 $$
->name
= new_name_id
();
482 $$
->name
->type
= name_ord
;
483 $$
->name
->name.i_name
= $1;
484 chat
("Got %s (%d)\n", get_typename
($3), $$
->name
->name.i_name
);
487 | tIDENT usrcvt resource_definition
{
491 $$
->name
= new_name_id
();
492 $$
->name
->type
= name_str
;
493 $$
->name
->name.s_name
= $1;
494 chat
("Got %s (%s)\n", get_typename
($3), $$
->name
->name.s_name
->str.cstr
);
498 /* Don't do anything, stringtables are converted to
499 * resource_t structures when we are finished parsing and
500 * the final rule of the parser is reduced (see above)
503 chat
("Got STRINGTABLE\n");
505 | tLANGUAGE
{want_nl
= 1; } expr
',' expr
{
506 /* We *NEED* the newline to delimit the expression.
507 * Otherwise, we would not be able to set the next
508 * want_id anymore because of the token-lookahead.
510 * However, we can test the lookahead-token for
511 * being "non-expression" type, in which case we
512 * continue. Fortunately, tNL is the only token that
513 * will break expression parsing and is implicitly
514 * void, so we just remove it. This scheme makes it
515 * possible to do some (not all) fancy preprocessor
517 * BTW, we also need to make sure that the next
518 * reduction of 'resources' above will *not* set
519 * want_id because we already have a lookahead that
522 if
(yychar != YYEMPTY
&& yychar != tNL
)
526 yychar = YYEMPTY
; /* Could use 'yyclearin', but we already need the*/
527 /* direct access to yychar in rule 'usrcvt' below. */
528 else if
(yychar == tIDENT
)
529 parser_warning
("LANGUAGE statement not delimited with newline; next identifier might be wrong\n");
531 want_nl
= 0; /* We don't want it anymore if we didn't get it */
534 parser_warning
("LANGUAGE not supported in 16-bit mode\n");
535 free
(currentlanguage
);
536 if
(get_language_codepage
($3, $5) == -1)
537 yyerror( "Language %04x is not supported", ($5<<10) + $3);
538 currentlanguage
= new_language
($3, $5);
540 chat
("Got LANGUAGE %d,%d (0x%04x)\n", $3, $5, ($5<<10) + $3);
545 * Remapping of numerical resource types
546 * (see also comment of called function below)
548 usrcvt
: /* Empty */ { yychar = rsrcid_to_token
(yychar); }
552 * Get a valid name/id
555 if
($1 > 65535 ||
$1 < -32768)
556 yyerror("Resource's ID out of range (%d)", $1);
559 $$
->name.i_name
= $1;
564 $$
->name.s_name
= $1;
569 * Extra string recognition for CLASS statement in dialogs
571 nameid_s: nameid
{ $$
= $1; }
575 $$
->name.s_name
= $1;
579 /* get the value for a single resource*/
581 : accelerators
{ $$
= new_resource
(res_acc
, $1, $1->memopt
, $1->lvc.language
); }
582 | bitmap
{ $$
= new_resource
(res_bmp
, $1, $1->memopt
, $1->data
->lvc.language
); }
585 if
($1->type
== res_anicur
)
587 $$
= rsc
= new_resource
(res_anicur
, $1->u.ani
, $1->u.ani
->memopt
, $1->u.ani
->data
->lvc.language
);
589 else if
($1->type
== res_curg
)
592 $$
= rsc
= new_resource
(res_curg
, $1->u.curg
, $1->u.curg
->memopt
, $1->u.curg
->lvc.language
);
593 for
(cur
= $1->u.curg
->cursorlist
; cur
; cur
= cur
->next
)
595 rsc
->prev
= new_resource
(res_cur
, cur
, $1->u.curg
->memopt
, $1->u.curg
->lvc.language
);
596 rsc
->prev
->next
= rsc
;
598 rsc
->name
= new_name_id
();
599 rsc
->name
->type
= name_ord
;
600 rsc
->name
->name.i_name
= cur
->id
;
604 internal_error
(__FILE__
, __LINE__
, "Invalid top-level type %d in cursor resource\n", $1->type
);
607 | dialog
{ $$
= new_resource
(res_dlg
, $1, $1->memopt
, $1->lvc.language
); }
610 $$
= new_resource
(res_dlgex
, $1, $1->memopt
, $1->lvc.language
);
614 | dlginit
{ $$
= new_resource
(res_dlginit
, $1, $1->memopt
, $1->data
->lvc.language
); }
615 | font
{ $$
= new_resource
(res_fnt
, $1, $1->memopt
, $1->data
->lvc.language
); }
616 | fontdir
{ $$
= new_resource
(res_fntdir
, $1, $1->memopt
, $1->data
->lvc.language
); }
619 if
($1->type
== res_aniico
)
621 $$
= rsc
= new_resource
(res_aniico
, $1->u.ani
, $1->u.ani
->memopt
, $1->u.ani
->data
->lvc.language
);
623 else if
($1->type
== res_icog
)
626 $$
= rsc
= new_resource
(res_icog
, $1->u.icog
, $1->u.icog
->memopt
, $1->u.icog
->lvc.language
);
627 for
(ico
= $1->u.icog
->iconlist
; ico
; ico
= ico
->next
)
629 rsc
->prev
= new_resource
(res_ico
, ico
, $1->u.icog
->memopt
, $1->u.icog
->lvc.language
);
630 rsc
->prev
->next
= rsc
;
632 rsc
->name
= new_name_id
();
633 rsc
->name
->type
= name_ord
;
634 rsc
->name
->name.i_name
= ico
->id
;
638 internal_error
(__FILE__
, __LINE__
, "Invalid top-level type %d in icon resource\n", $1->type
);
641 | menu
{ $$
= new_resource
(res_men
, $1, $1->memopt
, $1->lvc.language
); }
644 $$
= new_resource
(res_menex
, $1, $1->memopt
, $1->lvc.language
);
648 | messagetable
{ $$
= new_resource
(res_msg
, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE
, $1->data
->lvc.language
); }
649 | html
{ $$
= new_resource
(res_html
, $1, $1->memopt
, $1->data
->lvc.language
); }
650 | rcdata
{ $$
= new_resource
(res_rdt
, $1, $1->memopt
, $1->data
->lvc.language
); }
651 | toolbar
{ $$
= new_resource
(res_toolbar
, $1, $1->memopt
, $1->lvc.language
); }
652 | userres
{ $$
= new_resource
(res_usr
, $1, $1->memopt
, $1->data
->lvc.language
); }
653 | versioninfo
{ $$
= new_resource
(res_ver
, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE
, $1->lvc.language
); }
657 filename: tFILENAME
{ $$
= make_filename
($1); }
658 | tIDENT
{ $$
= make_filename
($1); }
659 | tSTRING
{ $$
= make_filename
($1); }
662 /* ------------------------------ Bitmap ------------------------------ */
663 bitmap
: tBITMAP loadmemopts file_raw
{ $$
= new_bitmap
($3, $2); }
666 /* ------------------------------ Cursor ------------------------------ */
667 cursor
: tCURSOR loadmemopts file_raw
{
669 if
($3->size
> 4 && !memcmp
($3->data
, riff
, sizeof
(riff
)))
671 $$
->type
= res_anicur
;
672 $$
->u.ani
= new_ani_curico
(res_anicur
, $3, $2);
677 $$
->u.curg
= new_cursor_group
($3, $2);
682 /* ------------------------------ Icon ------------------------------ */
683 icon
: tICON loadmemopts file_raw
{
685 if
($3->size
> 4 && !memcmp
($3->data
, riff
, sizeof
(riff
)))
687 $$
->type
= res_aniico
;
688 $$
->u.ani
= new_ani_curico
(res_aniico
, $3, $2);
693 $$
->u.icog
= new_icon_group
($3, $2);
698 /* ------------------------------ Font ------------------------------ */
700 * The reading of raw_data for fonts is a Borland BRC
701 * extension. MS generates an error. However, it is
702 * most logical to support this, considering how wine
703 * enters things in CVS (ascii).
705 font
: tFONT loadmemopts file_raw
{ $$
= new_font
($3, $2); }
709 * The fontdir is a Borland BRC extension which only
710 * reads the data as 'raw_data' from the file.
711 * I don't know whether it is interpreted.
712 * The fontdir is generated if it was not present and
713 * fonts are defined in the source.
715 fontdir
: tFONTDIR loadmemopts file_raw
{ $$
= new_fontdir
($3, $2); }
718 /* ------------------------------ MessageTable ------------------------------ */
719 /* It might be interesting to implement the MS Message compiler here as well
720 * to get everything in one source. Might be a future project.
723 : tMESSAGETABLE loadmemopts file_raw
{
725 parser_warning
("MESSAGETABLE not supported in 16-bit mode\n");
726 $$
= new_messagetable
($3, $2);
730 /* ------------------------------ HTML ------------------------------ */
731 html
: tHTML loadmemopts file_raw
{ $$
= new_html
($3, $2); }
734 /* ------------------------------ RCData ------------------------------ */
735 rcdata
: tRCDATA loadmemopts file_raw
{ $$
= new_rcdata
($3, $2); }
738 /* ------------------------------ DLGINIT ------------------------------ */
739 dlginit
: tDLGINIT loadmemopts file_raw
{ $$
= new_dlginit
($3, $2); }
742 /* ------------------------------ UserType ------------------------------ */
743 userres
: usertype loadmemopts file_raw
{
744 #ifdef WORDS_BIGENDIAN
745 if
(pedantic
&& byteorder
!= WRC_BO_LITTLE
)
747 if
(pedantic
&& byteorder
== WRC_BO_BIG
)
749 parser_warning
("Byteordering is not little-endian and type cannot be interpreted\n");
750 $$
= new_user
($1, $3, $2);
757 $$
->name.i_name
= $1;
762 $$
->name.s_name
= $1;
766 /* ------------------------------ Accelerator ------------------------------ */
768 : tACCELERATORS loadmemopts opt_lvc tBEGIN events tEND
{
769 $$
= new_accelerator
();
777 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE
;
780 yyerror("Accelerator table must have at least one entry");
781 $$
->events
= get_event_head
($5);
787 if
(!$$
->lvc.language
)
788 $$
->lvc.language
= dup_language
(currentlanguage
);
792 events
: /* Empty */ { $$
=NULL
; }
793 | events tSTRING
',' expr acc_opt
{ $$
=add_string_event
($2, $4, $5, $1); }
794 | events expr
',' expr acc_opt
{ $$
=add_event
($2, $4, $5, $1); }
798 * The empty rule generates a s/r conflict because of {bi,u}nary expr
799 * on - and +. It cannot be solved in any way because it is the same as
800 * the if/then/else problem (LALR(1) problem). The conflict is moved
801 * away by forcing it to be in the expression handling below.
803 acc_opt
: /* Empty */ { $$
= 0; }
804 |
',' accs
{ $$
= $2; }
807 accs
: acc
{ $$
= $1; }
808 | accs
',' acc
{ $$
= $1 |
$3; }
811 acc
: tNOINVERT
{ $$
= WRC_AF_NOINVERT
; }
812 | tSHIFT
{ $$
= WRC_AF_SHIFT
; }
813 | tCONTROL
{ $$
= WRC_AF_CONTROL
; }
814 | tALT
{ $$
= WRC_AF_ALT
; }
815 | tASCII
{ $$
= WRC_AF_ASCII
; }
816 | tVIRTKEY
{ $$
= WRC_AF_VIRTKEY
; }
819 /* ------------------------------ Dialog ------------------------------ */
820 /* FIXME: Support EXSTYLE in the dialog line itself */
821 dialog
: tDIALOG loadmemopts expr
',' expr
',' expr
',' expr dlg_attributes
829 $10->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
834 $10->controls
= get_control_head
($12);
838 $$
->style
= new_style
(0,0);
839 $$
->style
->or_mask
= WS_POPUP
;
843 $$
->style
->or_mask |
= WS_CAPTION
;
845 $$
->style
->or_mask |
= DS_SETFONT
;
847 $$
->style
->or_mask
&= ~
($$
->style
->and_mask
);
848 $$
->style
->and_mask
= 0;
850 if
(!$$
->lvc.language
)
851 $$
->lvc.language
= dup_language
(currentlanguage
);
856 : /* Empty */ { $$
=new_dialog
(); }
857 | dlg_attributes tSTYLE style
{ $$
=dialog_style
($3,$1); }
858 | dlg_attributes tEXSTYLE style
{ $$
=dialog_exstyle
($3,$1); }
859 | dlg_attributes tCAPTION tSTRING
{ $$
=dialog_caption
($3,$1); }
860 | dlg_attributes opt_font
{ $$
=dialog_font
($2,$1); }
861 | dlg_attributes tCLASS nameid_s
{ $$
=dialog_class
($3,$1); }
862 | dlg_attributes tMENU nameid
{ $$
=dialog_menu
($3,$1); }
863 | dlg_attributes opt_language
{ $$
=dialog_language
($2,$1); }
864 | dlg_attributes opt_characts
{ $$
=dialog_characteristics
($2,$1); }
865 | dlg_attributes opt_version
{ $$
=dialog_version
($2,$1); }
868 ctrls
: /* Empty */ { $$
= NULL
; }
869 | ctrls tCONTROL gen_ctrl
{ $$
=ins_ctrl
(-1, 0, $3, $1); }
870 | ctrls tEDITTEXT ctrl_desc
{ $$
=ins_ctrl
(CT_EDIT
, 0, $3, $1); }
871 | ctrls tLISTBOX ctrl_desc
{ $$
=ins_ctrl
(CT_LISTBOX
, 0, $3, $1); }
872 | ctrls tCOMBOBOX ctrl_desc
{ $$
=ins_ctrl
(CT_COMBOBOX
, 0, $3, $1); }
873 | ctrls tSCROLLBAR ctrl_desc
{ $$
=ins_ctrl
(CT_SCROLLBAR
, 0, $3, $1); }
874 | ctrls tCHECKBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_CHECKBOX
, $3, $1); }
875 | ctrls tDEFPUSHBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_DEFPUSHBUTTON
, $3, $1); }
876 | ctrls tGROUPBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_GROUPBOX
, $3, $1);}
877 | ctrls tPUSHBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_PUSHBUTTON
, $3, $1); }
878 /* | ctrls tPUSHBOX lab_ctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
879 | ctrls tRADIOBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_RADIOBUTTON
, $3, $1); }
880 | ctrls tAUTO3STATE lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTO3STATE
, $3, $1); }
881 | ctrls tSTATE3 lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_3STATE
, $3, $1); }
882 | ctrls tAUTOCHECKBOX lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTOCHECKBOX
, $3, $1); }
883 | ctrls tAUTORADIOBUTTON lab_ctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTORADIOBUTTON
, $3, $1); }
884 | ctrls tLTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_LEFT
, $3, $1); }
885 | ctrls tCTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_CENTER
, $3, $1); }
886 | ctrls tRTEXT lab_ctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_RIGHT
, $3, $1); }
887 /* special treatment for icons, as the extent is optional */
888 | ctrls tICON nameid_s opt_comma expr
',' expr
',' expr iconinfo
{
893 $$
= ins_ctrl
(CT_STATIC
, SS_ICON
, $10, $1);
898 : nameid_s opt_comma expr
',' expr
',' expr
',' expr
',' expr optional_style_pair
{
908 $$
->style
= $12->style
;
912 $$
->exstyle
= $12->exstyle
;
913 $$
->gotexstyle
= TRUE
;
921 : expr
',' expr
',' expr
',' expr
',' expr optional_style_pair
{
930 $$
->style
= $10->style
;
934 $$
->exstyle
= $10->exstyle
;
935 $$
->gotexstyle
= TRUE
;
942 iconinfo: /* Empty */
943 { $$
= new_control
(); }
945 |
',' expr
',' expr
{
950 |
',' expr
',' expr
',' style
{
957 |
',' expr
',' expr
',' style
',' style
{
964 $$
->gotexstyle
= TRUE
;
968 gen_ctrl: nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr
',' style
{
972 $$
->ctlclass
= convert_ctlclass
($5);
980 $$
->gotexstyle
= TRUE
;
982 | nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr
{
986 $$
->ctlclass
= convert_ctlclass
($5);
997 : tFONT expr
',' tSTRING
{ $$
= new_font_id
($2, $4, 0, 0); }
1000 /* ------------------------------ style flags ------------------------------ */
1002 : /* Empty */ { $$
= NULL
; }
1003 |
',' style
{ $$
= new_style_pair
($2, 0); }
1004 |
',' style
',' style
{ $$
= new_style_pair
($2, $4); }
1008 : style
'|' style
{ $$
= new_style
($1->or_mask |
$3->or_mask
, $1->and_mask |
$3->and_mask
); free
($1); free
($3);}
1009 |
'(' style
')' { $$
= $2; }
1010 | any_num
{ $$
= new_style
($1, 0); }
1011 | tNOT any_num
{ $$
= new_style
(0, $2); }
1017 $$
->type
= name_ord
;
1018 $$
->name.i_name
= $1;
1022 $$
->type
= name_str
;
1023 $$
->name.s_name
= $1;
1027 /* ------------------------------ DialogEx ------------------------------ */
1028 dialogex: tDIALOGEX loadmemopts expr
',' expr
',' expr
',' expr helpid dlgex_attribs
1029 tBEGIN exctrls tEND
{
1031 parser_warning
("DIALOGEX not supported in 16-bit mode\n");
1034 $11->memopt
= *($2);
1038 $11->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1045 $11->helpid
= *($10);
1046 $11->gothelpid
= TRUE
;
1049 $11->controls
= get_control_head
($13);
1052 assert
($$
->style
!= NULL
);
1055 $$
->style
->or_mask
= WS_POPUP
;
1056 $$
->gotstyle
= TRUE
;
1059 $$
->style
->or_mask |
= WS_CAPTION
;
1061 $$
->style
->or_mask |
= DS_SETFONT
;
1063 $$
->style
->or_mask
&= ~
($$
->style
->and_mask
);
1064 $$
->style
->and_mask
= 0;
1066 if
(!$$
->lvc.language
)
1067 $$
->lvc.language
= dup_language
(currentlanguage
);
1072 : /* Empty */ { $$
=new_dialogex
(); }
1073 | dlgex_attribs tSTYLE style
{ $$
=dialogex_style
($3,$1); }
1074 | dlgex_attribs tEXSTYLE style
{ $$
=dialogex_exstyle
($3,$1); }
1075 | dlgex_attribs tCAPTION tSTRING
{ $$
=dialogex_caption
($3,$1); }
1076 | dlgex_attribs opt_font
{ $$
=dialogex_font
($2,$1); }
1077 | dlgex_attribs opt_exfont
{ $$
=dialogex_font
($2,$1); }
1078 | dlgex_attribs tCLASS nameid_s
{ $$
=dialogex_class
($3,$1); }
1079 | dlgex_attribs tMENU nameid
{ $$
=dialogex_menu
($3,$1); }
1080 | dlgex_attribs opt_language
{ $$
=dialogex_language
($2,$1); }
1081 | dlgex_attribs opt_characts
{ $$
=dialogex_characteristics
($2,$1); }
1082 | dlgex_attribs opt_version
{ $$
=dialogex_version
($2,$1); }
1085 exctrls
: /* Empty */ { $$
= NULL
; }
1086 | exctrls tCONTROL gen_exctrl
{ $$
=ins_ctrl
(-1, 0, $3, $1); }
1087 | exctrls tEDITTEXT exctrl_desc
{ $$
=ins_ctrl
(CT_EDIT
, 0, $3, $1); }
1088 | exctrls tLISTBOX exctrl_desc
{ $$
=ins_ctrl
(CT_LISTBOX
, 0, $3, $1); }
1089 | exctrls tCOMBOBOX exctrl_desc
{ $$
=ins_ctrl
(CT_COMBOBOX
, 0, $3, $1); }
1090 | exctrls tSCROLLBAR exctrl_desc
{ $$
=ins_ctrl
(CT_SCROLLBAR
, 0, $3, $1); }
1091 | exctrls tCHECKBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_CHECKBOX
, $3, $1); }
1092 | exctrls tDEFPUSHBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_DEFPUSHBUTTON
, $3, $1); }
1093 | exctrls tGROUPBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_GROUPBOX
, $3, $1);}
1094 | exctrls tPUSHBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_PUSHBUTTON
, $3, $1); }
1095 /* | exctrls tPUSHBOX lab_exctrl { $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
1096 | exctrls tRADIOBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_RADIOBUTTON
, $3, $1); }
1097 | exctrls tAUTO3STATE lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTO3STATE
, $3, $1); }
1098 | exctrls tSTATE3 lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_3STATE
, $3, $1); }
1099 | exctrls tAUTOCHECKBOX lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTOCHECKBOX
, $3, $1); }
1100 | exctrls tAUTORADIOBUTTON lab_exctrl
{ $$
=ins_ctrl
(CT_BUTTON
, BS_AUTORADIOBUTTON
, $3, $1); }
1101 | exctrls tLTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_LEFT
, $3, $1); }
1102 | exctrls tCTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_CENTER
, $3, $1); }
1103 | exctrls tRTEXT lab_exctrl
{ $$
=ins_ctrl
(CT_STATIC
, SS_RIGHT
, $3, $1); }
1104 /* special treatment for icons, as the extent is optional */
1105 | exctrls tICON nameid_s opt_comma expr
',' expr
',' expr iconinfo
{
1110 $$
= ins_ctrl
(CT_STATIC
, SS_ICON
, $10, $1);
1115 : nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
','
1116 expr
',' style helpid opt_data
{
1120 $$
->ctlclass
= convert_ctlclass
($5);
1122 $$
->gotstyle
= TRUE
;
1130 $$
->gotexstyle
= TRUE
;
1134 $$
->helpid
= *($18);
1135 $$
->gothelpid
= TRUE
;
1140 | nameid_s opt_comma expr
',' ctlclass
',' style
',' expr
',' expr
',' expr
',' expr opt_data
{
1145 $$
->gotstyle
= TRUE
;
1146 $$
->ctlclass
= convert_ctlclass
($5);
1156 : nameid_s opt_comma expr
',' expr
',' expr
',' expr
',' expr optional_style_pair helpid opt_data
{
1166 $$
->style
= $12->style
;
1167 $$
->gotstyle
= TRUE
;
1171 $$
->exstyle
= $12->exstyle
;
1172 $$
->gotexstyle
= TRUE
;
1182 : expr
',' expr
',' expr
',' expr
',' expr optional_style_pair helpid opt_data
{
1191 $$
->style
= $10->style
;
1192 $$
->gotstyle
= TRUE
;
1196 $$
->exstyle
= $10->exstyle
;
1197 $$
->gotexstyle
= TRUE
;
1205 opt_data: /* Empty */ { $$
= NULL
; }
1206 | raw_data
{ $$
= $1; }
1209 helpid
: /* Empty */ { $$
= NULL
; }
1210 |
',' expr
{ $$
= new_int
($2); }
1214 : tFONT expr
',' tSTRING
',' expr
',' expr opt_expr
{ $$
= new_font_id
($2, $4, $6, $8); }
1218 * FIXME: This odd expression is here to nullify an extra token found
1219 * in some appstudio produced resources which appear to do nothing.
1221 opt_expr: /* Empty */ { $$
= NULL
; }
1222 |
',' expr
{ $$
= NULL
; }
1225 /* ------------------------------ Menu ------------------------------ */
1226 menu
: tMENU loadmemopts opt_lvc menu_body
{
1228 yyerror("Menu must contain items");
1236 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1237 $$
->items
= get_item_head
($4);
1243 if
(!$$
->lvc.language
)
1244 $$
->lvc.language
= dup_language
(currentlanguage
);
1249 : tBEGIN item_definitions tEND
{ $$
= $2; }
1253 : /* Empty */ {$$
= NULL
;}
1254 | item_definitions tMENUITEM tSTRING opt_comma expr item_options
{
1263 | item_definitions tMENUITEM tSEPARATOR
{
1269 | item_definitions tPOPUP tSTRING item_options menu_body
{
1270 $$
= new_menu_item
();
1274 $$
->popup
= get_item_head
($5);
1279 /* NOTE: item_options is right recursive because it would introduce
1280 * a shift/reduce conflict on ',' in itemex_options due to the
1281 * empty rule here. The parser is now forced to look beyond the ','
1282 * before reducing (force shift).
1283 * Right recursion here is not a problem because we cannot expect
1284 * more than 7 parserstack places to be occupied while parsing this
1285 * (who would want to specify a MF_x flag twice?).
1288 : /* Empty */ { $$
= 0; }
1289 | opt_comma tCHECKED item_options
{ $$
= $3 | MF_CHECKED
; }
1290 | opt_comma tGRAYED item_options
{ $$
= $3 | MF_GRAYED
; }
1291 | opt_comma tHELP item_options
{ $$
= $3 | MF_HELP
; }
1292 | opt_comma tINACTIVE item_options
{ $$
= $3 | MF_DISABLED
; }
1293 | opt_comma tMENUBARBREAK item_options
{ $$
= $3 | MF_MENUBARBREAK
; }
1294 | opt_comma tMENUBREAK item_options
{ $$
= $3 | MF_MENUBREAK
; }
1297 /* ------------------------------ MenuEx ------------------------------ */
1298 menuex
: tMENUEX loadmemopts opt_lvc menuex_body
{
1300 parser_warning
("MENUEX not supported in 16-bit mode\n");
1302 yyerror("MenuEx must contain items");
1310 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE
;
1311 $$
->items
= get_itemex_head
($4);
1317 if
(!$$
->lvc.language
)
1318 $$
->lvc.language
= dup_language
(currentlanguage
);
1323 : tBEGIN itemex_definitions tEND
{ $$
= $2; }
1327 : /* Empty */ {$$
= NULL
; }
1328 | itemex_definitions tMENUITEM tSTRING itemex_options
{
1329 $$
= new_menuex_item
();
1335 $$
->type
= $4->type
;
1336 $$
->state
= $4->state
;
1337 $$
->helpid
= $4->helpid
;
1338 $$
->gotid
= $4->gotid
;
1339 $$
->gottype
= $4->gottype
;
1340 $$
->gotstate
= $4->gotstate
;
1341 $$
->gothelpid
= $4->gothelpid
;
1344 | itemex_definitions tMENUITEM tSEPARATOR
{
1345 $$
= new_menuex_item
();
1350 | itemex_definitions tPOPUP tSTRING itemex_p_options menuex_body
{
1351 $$
= new_menuex_item
();
1355 $$
->popup
= get_itemex_head
($5);
1358 $$
->type
= $4->type
;
1359 $$
->state
= $4->state
;
1360 $$
->helpid
= $4->helpid
;
1361 $$
->gotid
= $4->gotid
;
1362 $$
->gottype
= $4->gottype
;
1363 $$
->gotstate
= $4->gotstate
;
1364 $$
->gothelpid
= $4->gothelpid
;
1370 : /* Empty */ { $$
= new_itemex_opt
(0, 0, 0, 0); }
1372 $$
= new_itemex_opt
($2, 0, 0, 0);
1375 |
',' e_expr
',' e_expr item_options
{
1376 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $5, 0);
1379 $$
->gotstate
= TRUE
;
1383 |
',' e_expr
',' e_expr
',' expr
{
1384 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6, 0);
1387 $$
->gotstate
= TRUE
;
1394 : /* Empty */ { $$
= new_itemex_opt
(0, 0, 0, 0); }
1396 $$
= new_itemex_opt
($2, 0, 0, 0);
1399 |
',' e_expr
',' expr
{
1400 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4, 0, 0);
1405 |
',' e_expr
',' e_expr
',' expr
{
1406 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6, 0);
1411 $$
->gotstate
= TRUE
;
1413 |
',' e_expr
',' e_expr
',' e_expr
',' expr
{
1414 $$
= new_itemex_opt
($2 ?
*($2) : 0, $4 ?
*($4) : 0, $6 ?
*($6) : 0, $8);
1420 $$
->gotstate
= TRUE
;
1421 $$
->gothelpid
= TRUE
;
1425 /* ------------------------------ StringTable ------------------------------ */
1426 /* Stringtables are parsed differently than other resources because their
1427 * layout is substantially different from other resources.
1428 * The table is parsed through a _global_ variable 'tagstt' which holds the
1429 * current stringtable descriptor (stringtable_t *) and 'sttres' that holds a
1430 * list of stringtables of different languages.
1433 : stt_head tBEGIN strings tEND
{
1436 yyerror("Stringtable must have at least one entry");
1441 /* Check if we added to a language table or created
1444 for
(stt
= sttres
; stt
; stt
= stt
->next
)
1451 /* It is a new one */
1454 sttres
->prev
= tagstt
;
1455 tagstt
->next
= sttres
;
1461 /* Else were done */
1463 free
(tagstt_memopt
);
1464 tagstt_memopt
= NULL
;
1470 /* This is to get the language of the currently parsed stringtable */
1471 stt_head: tSTRINGTABLE loadmemopts opt_lvc
{
1472 if
((tagstt
= find_stringtable
($3)) == NULL
)
1473 tagstt
= new_stringtable
($3);
1475 tagstt_version
= $3->version
;
1476 tagstt_characts
= $3->characts
;
1481 strings
: /* Empty */ { $$
= NULL
; }
1482 | strings expr opt_comma tSTRING
{
1484 assert
(tagstt
!= NULL
);
1485 if
($2 > 65535 ||
$2 < -32768)
1486 yyerror("Stringtable entry's ID out of range (%d)", $2);
1487 /* Search for the ID */
1488 for
(i
= 0; i
< tagstt
->nentries
; i
++)
1490 if
(tagstt
->entries
[i
].id
== $2)
1491 yyerror("Stringtable ID %d already in use", $2);
1493 /* If we get here, then we have a new unique entry */
1495 tagstt
->entries
= xrealloc
(tagstt
->entries
, sizeof
(tagstt
->entries
[0]) * tagstt
->nentries
);
1496 tagstt
->entries
[tagstt
->nentries
-1].id
= $2;
1497 tagstt
->entries
[tagstt
->nentries
-1].str
= $4;
1499 tagstt
->entries
[tagstt
->nentries
-1].memopt
= *tagstt_memopt
;
1501 tagstt
->entries
[tagstt
->nentries
-1].memopt
= WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE
;
1502 tagstt
->entries
[tagstt
->nentries
-1].version
= tagstt_version
;
1503 tagstt
->entries
[tagstt
->nentries
-1].characts
= tagstt_characts
;
1505 if
(pedantic
&& !$4->size
)
1506 parser_warning
("Zero length strings make no sense\n");
1507 if
(!win32
&& $4->size
> 254)
1508 yyerror("Stringtable entry more than 254 characters");
1509 if
(win32
&& $4->size
> 65534) /* Hmm..., does this happen? */
1510 yyerror("Stringtable entry more than 65534 characters (probably something else that went wrong)");
1515 opt_comma
/* There seem to be two ways to specify a stringtable... */
1520 /* ------------------------------ VersionInfo ------------------------------ */
1522 : tVERSIONINFO loadmemopts fix_version tBEGIN ver_blocks tEND
{
1530 $$
->memopt
= WRC_MO_MOVEABLE |
(win32 ? WRC_MO_PURE
: 0);
1531 $$
->blocks
= get_ver_block_head
($5);
1532 /* Set language; there is no version or characteristics */
1533 $$
->lvc.language
= dup_language
(currentlanguage
);
1538 : /* Empty */ { $$
= new_versioninfo
(); }
1539 | fix_version tFILEVERSION expr
',' expr
',' expr
',' expr
{
1541 yyerror("FILEVERSION already defined");
1543 $$
->filever_maj1
= $3;
1544 $$
->filever_maj2
= $5;
1545 $$
->filever_min1
= $7;
1546 $$
->filever_min2
= $9;
1549 | fix_version tPRODUCTVERSION expr
',' expr
',' expr
',' expr
{
1551 yyerror("PRODUCTVERSION already defined");
1553 $$
->prodver_maj1
= $3;
1554 $$
->prodver_maj2
= $5;
1555 $$
->prodver_min1
= $7;
1556 $$
->prodver_min2
= $9;
1559 | fix_version tFILEFLAGS expr
{
1561 yyerror("FILEFLAGS already defined");
1566 | fix_version tFILEFLAGSMASK expr
{
1568 yyerror("FILEFLAGSMASK already defined");
1570 $$
->fileflagsmask
= $3;
1573 | fix_version tFILEOS expr
{
1575 yyerror("FILEOS already defined");
1580 | fix_version tFILETYPE expr
{
1582 yyerror("FILETYPE already defined");
1587 | fix_version tFILESUBTYPE expr
{
1589 yyerror("FILESUBTYPE already defined");
1591 $$
->filesubtype
= $3;
1597 : /* Empty */ { $$
= NULL
; }
1598 | ver_blocks ver_block
{
1607 : tBLOCK tSTRING tBEGIN ver_values tEND
{
1608 $$
= new_ver_block
();
1610 $$
->values
= get_ver_value_head
($4);
1615 : /* Empty */ { $$
= NULL
; }
1616 | ver_values ver_value
{
1626 $$
= new_ver_value
();
1627 $$
->type
= val_block
;
1628 $$
->value.block
= $1;
1630 | tVALUE tSTRING
',' tSTRING
{
1631 $$
= new_ver_value
();
1636 | tVALUE tSTRING
',' ver_words
{
1637 $$
= new_ver_value
();
1638 $$
->type
= val_words
;
1640 $$
->value.words
= $4;
1645 : expr
{ $$
= new_ver_words
($1); }
1646 | ver_words
',' expr
{ $$
= add_ver_words
($1, $3); }
1649 /* ------------------------------ Toolbar ------------------------------ */
1650 toolbar: tTOOLBAR loadmemopts expr
',' expr opt_lvc tBEGIN toolbar_items tEND
{
1652 toolbar_item_t
*items
= get_tlbr_buttons_head
($8, &nitems
);
1653 $$
= new_toolbar
($3, $5, items
, nitems
);
1661 $$
->memopt
= WRC_MO_MOVEABLE | WRC_MO_PURE
;
1668 if
(!$$
->lvc.language
)
1670 $$
->lvc.language
= dup_language
(currentlanguage
);
1676 : /* Empty */ { $$
= NULL
; }
1677 | toolbar_items tBUTTON expr
{
1678 toolbar_item_t
*idrec
= new_toolbar_item
();
1680 $$
= ins_tlbr_button
($1, idrec
);
1682 | toolbar_items tSEPARATOR
{
1683 toolbar_item_t
*idrec
= new_toolbar_item
();
1685 $$
= ins_tlbr_button
($1, idrec
);
1689 /* ------------------------------ Memory options ------------------------------ */
1691 : /* Empty */ { $$
= NULL
; }
1692 | loadmemopts lamo
{
1702 | loadmemopts lama
{
1711 *$2 &= WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE
;
1717 lamo
: tPRELOAD
{ $$
= new_int
(WRC_MO_PRELOAD
); }
1718 | tMOVEABLE
{ $$
= new_int
(WRC_MO_MOVEABLE
); }
1719 | tDISCARDABLE
{ $$
= new_int
(WRC_MO_DISCARDABLE
); }
1720 | tPURE
{ $$
= new_int
(WRC_MO_PURE
); }
1723 lama
: tLOADONCALL
{ $$
= new_int
(~WRC_MO_PRELOAD
); }
1724 | tFIXED
{ $$
= new_int
(~WRC_MO_MOVEABLE
); }
1725 | tIMPURE
{ $$
= new_int
(~WRC_MO_PURE
); }
1728 /* ------------------------------ Win32 options ------------------------------ */
1729 opt_lvc
: /* Empty */ { $$
= new_lvc
(); }
1730 | opt_lvc opt_language
{
1732 parser_warning
("LANGUAGE not supported in 16-bit mode\n");
1734 yyerror("Language already defined");
1738 | opt_lvc opt_characts
{
1740 parser_warning
("CHARACTERISTICS not supported in 16-bit mode\n");
1742 yyerror("Characteristics already defined");
1746 | opt_lvc opt_version
{
1748 parser_warning
("VERSION not supported in 16-bit mode\n");
1750 yyerror("Version already defined");
1757 * This here is another s/r conflict on {bi,u}nary + and -.
1758 * It is due to the look-ahead which must determine when the
1759 * rule opt_language ends. It could be solved with adding a
1760 * tNL at the end, but that seems unreasonable to do.
1761 * The conflict is now moved to the expression handling below.
1764 : tLANGUAGE expr
',' expr
{ $$
= new_language
($2, $4);
1765 if
(get_language_codepage
($2, $4) == -1)
1766 yyerror( "Language %04x is not supported", ($4<<10) + $2);
1771 : tCHARACTERISTICS expr
{ $$
= new_characts
($2); }
1775 : tVERSION expr
{ $$
= new_version
($2); }
1778 /* ------------------------------ Raw data handling ------------------------------ */
1779 raw_data: opt_lvc tBEGIN raw_elements tEND
{
1786 if
(!$3->lvc.language
)
1787 $3->lvc.language
= dup_language
(currentlanguage
);
1794 : tRAWDATA
{ $$
= $1; }
1795 | tNUMBER
{ $$
= int2raw_data
($1); }
1796 |
'-' tNUMBER
{ $$
= int2raw_data
(-($2)); }
1797 | tLNUMBER
{ $$
= long2raw_data
($1); }
1798 |
'-' tLNUMBER
{ $$
= long2raw_data
(-($2)); }
1799 | tSTRING
{ $$
= str2raw_data
($1); }
1800 | raw_elements opt_comma tRAWDATA
{ $$
= merge_raw_data
($1, $3); free
($3->data
); free
($3); }
1801 | raw_elements opt_comma tNUMBER
{ $$
= merge_raw_data_int
($1, $3); }
1802 | raw_elements opt_comma
'-' tNUMBER
{ $$
= merge_raw_data_int
($1, -($4)); }
1803 | raw_elements opt_comma tLNUMBER
{ $$
= merge_raw_data_long
($1, $3); }
1804 | raw_elements opt_comma
'-' tLNUMBER
{ $$
= merge_raw_data_long
($1, -($4)); }
1805 | raw_elements opt_comma tSTRING
{ $$
= merge_raw_data_str
($1, $3); }
1808 /* File data or raw data */
1809 file_raw: filename
{ $$
= load_file
($1,dup_language
(currentlanguage
)); }
1810 | raw_data
{ $$
= $1; }
1813 /* ------------------------------ Win32 expressions ------------------------------ */
1814 /* All win16 numbers are also handled here. This is inconsistent with MS'
1815 * resource compiler, but what the heck, its just handy to have.
1817 e_expr
: /* Empty */ { $$
= 0; }
1818 | expr
{ $$
= new_int
($1); }
1821 /* This rule moves ALL s/r conflicts on {bi,u}nary - and + to here */
1822 expr
: xpr
{ $$
= ($1); }
1825 xpr
: xpr
'+' xpr
{ $$
= ($1) + ($3); }
1826 | xpr
'-' xpr
{ $$
= ($1) - ($3); }
1827 | 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
{ $$
= ~
($2); }
1833 |
'-' xpr %prec pUPM
{ $$
= -($2); }
1834 |
'+' xpr %prec pUPM
{ $$
= $2; }
1835 |
'(' xpr
')' { $$
= $2; }
1836 | any_num
{ $$
= $1; }
1837 | tNOT any_num
{ $$
= ~
($2); }
1840 any_num
: tNUMBER
{ $$
= $1; }
1841 | tLNUMBER
{ $$
= $1; }
1845 /* Dialog specific functions */
1846 static dialog_t
*dialog_style
(style_t
* st
, dialog_t
*dlg
)
1848 assert
(dlg
!= NULL
);
1849 if
(dlg
->style
== NULL
)
1851 dlg
->style
= new_style
(0,0);
1856 parser_warning
("Style already defined, or-ing together\n");
1860 dlg
->style
->or_mask
= 0;
1861 dlg
->style
->and_mask
= 0;
1863 dlg
->style
->or_mask |
= st
->or_mask
;
1864 dlg
->style
->and_mask |
= st
->and_mask
;
1865 dlg
->gotstyle
= TRUE
;
1870 static dialog_t
*dialog_exstyle
(style_t
*st
, dialog_t
*dlg
)
1872 assert
(dlg
!= NULL
);
1873 if
(dlg
->exstyle
== NULL
)
1875 dlg
->exstyle
= new_style
(0,0);
1880 parser_warning
("ExStyle already defined, or-ing together\n");
1884 dlg
->exstyle
->or_mask
= 0;
1885 dlg
->exstyle
->and_mask
= 0;
1887 dlg
->exstyle
->or_mask |
= st
->or_mask
;
1888 dlg
->exstyle
->and_mask |
= st
->and_mask
;
1889 dlg
->gotexstyle
= TRUE
;
1894 static dialog_t
*dialog_caption
(string_t
*s
, dialog_t
*dlg
)
1896 assert
(dlg
!= NULL
);
1898 yyerror("Caption already defined");
1903 static dialog_t
*dialog_font
(font_id_t
*f
, dialog_t
*dlg
)
1905 assert
(dlg
!= NULL
);
1907 yyerror("Font already defined");
1912 static dialog_t
*dialog_class
(name_id_t
*n
, dialog_t
*dlg
)
1914 assert
(dlg
!= NULL
);
1916 yyerror("Class already defined");
1921 static dialog_t
*dialog_menu
(name_id_t
*m
, dialog_t
*dlg
)
1923 assert
(dlg
!= NULL
);
1925 yyerror("Menu already defined");
1930 static dialog_t
*dialog_language
(language_t
*l
, dialog_t
*dlg
)
1932 assert
(dlg
!= NULL
);
1933 if
(dlg
->lvc.language
)
1934 yyerror("Language already defined");
1935 dlg
->lvc.language
= l
;
1939 static dialog_t
*dialog_characteristics
(characts_t
*c
, dialog_t
*dlg
)
1941 assert
(dlg
!= NULL
);
1942 if
(dlg
->lvc.characts
)
1943 yyerror("Characteristics already defined");
1944 dlg
->lvc.characts
= c
;
1948 static dialog_t
*dialog_version
(version_t
*v
, dialog_t
*dlg
)
1950 assert
(dlg
!= NULL
);
1951 if
(dlg
->lvc.version
)
1952 yyerror("Version already defined");
1953 dlg
->lvc.version
= v
;
1957 /* Controls specific functions */
1958 static control_t
*ins_ctrl
(int type
, int special_style
, control_t
*ctrl
, control_t
*prev
)
1960 /* Hm... this seems to be jammed in at all time... */
1961 int defaultstyle
= WS_CHILD | WS_VISIBLE
;
1963 assert
(ctrl
!= NULL
);
1969 /* Check for duplicate identifiers */
1972 if
(ctrl
->id
!= -1 && ctrl
->id
== prev
->id
)
1973 parser_warning
("Duplicate dialog control id %d\n", ctrl
->id
);
1979 ctrl
->ctlclass
= new_name_id
();
1980 ctrl
->ctlclass
->type
= name_ord
;
1981 ctrl
->ctlclass
->name.i_name
= type
;
1987 if
(special_style
!= BS_GROUPBOX
&& special_style
!= BS_RADIOBUTTON
)
1988 defaultstyle |
= WS_TABSTOP
;
1991 defaultstyle |
= WS_TABSTOP | WS_BORDER
;
1994 defaultstyle |
= LBS_NOTIFY | WS_BORDER
;
1997 if
(!(ctrl
->style
->or_mask
& (CBS_SIMPLE | CBS_DROPDOWN | CBS_DROPDOWNLIST
)))
1998 defaultstyle |
= CBS_SIMPLE
;
2001 if
(special_style
== SS_CENTER || special_style
== SS_LEFT || special_style
== SS_RIGHT
)
2002 defaultstyle |
= WS_GROUP
;
2006 if
(!ctrl
->gotstyle
) /* Handle default style setting */
2011 defaultstyle |
= ES_LEFT
;
2014 defaultstyle |
= LBS_NOTIFY
;
2017 defaultstyle |
= CBS_SIMPLE | WS_TABSTOP
;
2020 defaultstyle |
= SBS_HORZ
;
2023 switch
(special_style
)
2026 case BS_DEFPUSHBUTTON
:
2028 /* case BS_PUSHBOX: */
2029 case BS_AUTORADIOBUTTON
:
2032 case BS_AUTOCHECKBOX
:
2033 defaultstyle |
= WS_TABSTOP
;
2036 parser_warning
("Unknown default button control-style 0x%08x\n", special_style
);
2038 case BS_RADIOBUTTON
:
2044 switch
(special_style
)
2049 defaultstyle |
= WS_GROUP
;
2051 case SS_ICON
: /* Special case */
2054 parser_warning
("Unknown default static control-style 0x%08x\n", special_style
);
2058 case
-1: /* Generic control */
2062 yyerror("Internal error (report this): Got weird control type 0x%08x", type
);
2066 /* The SS_ICON flag is always forced in for icon controls */
2067 if
(type
== CT_STATIC
&& special_style
== SS_ICON
)
2068 defaultstyle |
= SS_ICON
;
2070 if
(!ctrl
->gotstyle
)
2071 ctrl
->style
= new_style
(0,0);
2073 /* combine all styles */
2074 ctrl
->style
->or_mask
= ctrl
->style
->or_mask | defaultstyle | special_style
;
2075 ctrl
->gotstyle
= TRUE
;
2077 /* combine with NOT mask */
2080 ctrl
->style
->or_mask
&= ~
(ctrl
->style
->and_mask
);
2081 ctrl
->style
->and_mask
= 0;
2083 if
(ctrl
->gotexstyle
)
2085 ctrl
->exstyle
->or_mask
&= ~
(ctrl
->exstyle
->and_mask
);
2086 ctrl
->exstyle
->and_mask
= 0;
2091 static int get_class_idW
(const WCHAR
*cc
)
2093 static const WCHAR szBUTTON
[] = {'B','U','T','T','O','N',0};
2094 static const WCHAR szCOMBOBOX
[] = {'C','O','M','B','O','B','O','X',0};
2095 static const WCHAR szLISTBOX
[] = {'L','I','S','T','B','O','X',0};
2096 static const WCHAR szEDIT
[] = {'E','D','I','T',0};
2097 static const WCHAR szSTATIC
[] = {'S','T','A','T','I','C',0};
2098 static const WCHAR szSCROLLBAR
[] = {'S','C','R','O','L','L','B','A','R',0};
2100 if
(!strcmpiW
(szBUTTON
, cc
))
2102 if
(!strcmpiW
(szCOMBOBOX
, cc
))
2104 if
(!strcmpiW
(szLISTBOX
, cc
))
2106 if
(!strcmpiW
(szEDIT
, cc
))
2108 if
(!strcmpiW
(szSTATIC
, cc
))
2110 if
(!strcmpiW
(szSCROLLBAR
, cc
))
2111 return CT_SCROLLBAR
;
2116 static int get_class_idA
(const char *cc
)
2118 if
(!strcasecmp
("BUTTON", cc
))
2120 if
(!strcasecmp
("COMBOBOX", cc
))
2122 if
(!strcasecmp
("LISTBOX", cc
))
2124 if
(!strcasecmp
("EDIT", cc
))
2126 if
(!strcasecmp
("STATIC", cc
))
2128 if
(!strcasecmp
("SCROLLBAR", cc
))
2129 return CT_SCROLLBAR
;
2135 static name_id_t
*convert_ctlclass
(name_id_t
*cls
)
2139 if
(cls
->type
== name_ord
)
2141 assert
(cls
->type
== name_str
);
2142 if
(cls
->name.s_name
->type
== str_unicode
)
2143 iclass
= get_class_idW
(cls
->name.s_name
->str.wstr
);
2145 iclass
= get_class_idA
(cls
->name.s_name
->str.cstr
);
2148 return cls
; /* No default, return user controlclass */
2150 free
(cls
->name.s_name
->str.cstr
);
2151 free
(cls
->name.s_name
);
2152 cls
->type
= name_ord
;
2153 cls
->name.i_name
= iclass
;
2157 /* DialogEx specific functions */
2158 static dialogex_t
*dialogex_style
(style_t
* st
, dialogex_t
*dlg
)
2160 assert
(dlg
!= NULL
);
2161 if
(dlg
->style
== NULL
)
2163 dlg
->style
= new_style
(0,0);
2168 parser_warning
("Style already defined, or-ing together\n");
2172 dlg
->style
->or_mask
= 0;
2173 dlg
->style
->and_mask
= 0;
2175 dlg
->style
->or_mask |
= st
->or_mask
;
2176 dlg
->style
->and_mask |
= st
->and_mask
;
2177 dlg
->gotstyle
= TRUE
;
2182 static dialogex_t
*dialogex_exstyle
(style_t
* st
, dialogex_t
*dlg
)
2184 assert
(dlg
!= NULL
);
2185 if
(dlg
->exstyle
== NULL
)
2187 dlg
->exstyle
= new_style
(0,0);
2192 parser_warning
("ExStyle already defined, or-ing together\n");
2196 dlg
->exstyle
->or_mask
= 0;
2197 dlg
->exstyle
->and_mask
= 0;
2199 dlg
->exstyle
->or_mask |
= st
->or_mask
;
2200 dlg
->exstyle
->and_mask |
= st
->and_mask
;
2201 dlg
->gotexstyle
= TRUE
;
2206 static dialogex_t
*dialogex_caption
(string_t
*s
, dialogex_t
*dlg
)
2208 assert
(dlg
!= NULL
);
2210 yyerror("Caption already defined");
2215 static dialogex_t
*dialogex_font
(font_id_t
*f
, dialogex_t
*dlg
)
2217 assert
(dlg
!= NULL
);
2219 yyerror("Font already defined");
2224 static dialogex_t
*dialogex_class
(name_id_t
*n
, dialogex_t
*dlg
)
2226 assert
(dlg
!= NULL
);
2228 yyerror("Class already defined");
2233 static dialogex_t
*dialogex_menu
(name_id_t
*m
, dialogex_t
*dlg
)
2235 assert
(dlg
!= NULL
);
2237 yyerror("Menu already defined");
2242 static dialogex_t
*dialogex_language
(language_t
*l
, dialogex_t
*dlg
)
2244 assert
(dlg
!= NULL
);
2245 if
(dlg
->lvc.language
)
2246 yyerror("Language already defined");
2247 dlg
->lvc.language
= l
;
2251 static dialogex_t
*dialogex_characteristics
(characts_t
*c
, dialogex_t
*dlg
)
2253 assert
(dlg
!= NULL
);
2254 if
(dlg
->lvc.characts
)
2255 yyerror("Characteristics already defined");
2256 dlg
->lvc.characts
= c
;
2260 static dialogex_t
*dialogex_version
(version_t
*v
, dialogex_t
*dlg
)
2262 assert
(dlg
!= NULL
);
2263 if
(dlg
->lvc.version
)
2264 yyerror("Version already defined");
2265 dlg
->lvc.version
= v
;
2269 /* Accelerator specific functions */
2270 static event_t
*add_event
(int key
, int id
, int flags
, event_t
*prev
)
2272 event_t
*ev
= new_event
();
2274 if
((flags
& (WRC_AF_VIRTKEY | WRC_AF_ASCII
)) == (WRC_AF_VIRTKEY | WRC_AF_ASCII
))
2275 yyerror("Cannot use both ASCII and VIRTKEY");
2279 ev
->flags
= flags
& ~WRC_AF_ASCII
;
2286 static event_t
*add_string_event
(string_t
*key
, int id
, int flags
, event_t
*prev
)
2289 event_t
*ev
= new_event
();
2291 if
(key
->type
== str_char
)
2293 if
((flags
& WRC_AF_VIRTKEY
) && (!isupper
(key
->str.cstr
[0] & 0xff) && !isdigit
(key
->str.cstr
[0] & 0xff)))
2294 yyerror("VIRTKEY code is not equal to ascii value");
2296 if
(key
->str.cstr
[0] == '^' && (flags
& WRC_AF_CONTROL
) != 0)
2298 yyerror("Cannot use both '^' and CONTROL modifier");
2300 else if
(key
->str.cstr
[0] == '^')
2302 keycode
= toupper
(key
->str.cstr
[1]) - '@';
2304 yyerror("Control-code out of range");
2307 keycode
= key
->str.cstr
[0];
2311 if
((flags
& WRC_AF_VIRTKEY
) && !isupperW
(key
->str.wstr
[0]) && !isdigitW
(key
->str.wstr
[0]))
2312 yyerror("VIRTKEY code is not equal to ascii value");
2314 if
(key
->str.wstr
[0] == '^' && (flags
& WRC_AF_CONTROL
) != 0)
2316 yyerror("Cannot use both '^' and CONTROL modifier");
2318 else if
(key
->str.wstr
[0] == '^')
2320 keycode
= toupperW
(key
->str.wstr
[1]) - '@';
2322 yyerror("Control-code out of range");
2325 keycode
= key
->str.wstr
[0];
2330 ev
->flags
= flags
& ~WRC_AF_ASCII
;
2337 /* MenuEx specific functions */
2338 static itemex_opt_t
*new_itemex_opt
(int id
, int type
, int state
, int helpid
)
2340 itemex_opt_t
*opt
= xmalloc
(sizeof
(itemex_opt_t
));
2341 memset
( opt
, 0, sizeof
(*opt
) );
2345 opt
->helpid
= helpid
;
2349 /* Raw data functions */
2350 static raw_data_t
*load_file
(string_t
*filename
, language_t
*lang
)
2356 int codepage
= get_language_codepage
(lang
->id
, lang
->sub
);
2358 /* FIXME: we may want to use utf-8 here */
2359 if
(codepage
<= 0 && filename
->type
!= str_char
)
2360 yyerror("Cannot convert filename to ASCII string");
2361 name
= convert_string
( filename
, str_char
, codepage
);
2362 if
(!(path
= wpp_find_include
(name
->str.cstr
, input_name
)))
2363 yyerror("Cannot open file %s", name
->str.cstr
);
2364 if
(!(fp
= fopen
( path
, "rb" )))
2365 yyerror("Cannot open file %s", name
->str.cstr
);
2367 rd
= new_raw_data
();
2368 fseek
(fp
, 0, SEEK_END
);
2369 rd
->size
= ftell
(fp
);
2370 fseek
(fp
, 0, SEEK_SET
);
2373 rd
->data
= xmalloc
(rd
->size
);
2374 fread
(rd
->data
, rd
->size
, 1, fp
);
2376 else rd
->data
= NULL
;
2378 rd
->lvc.language
= lang
;
2383 static raw_data_t
*int2raw_data
(int i
)
2387 if
( ( i
>= 0 && (int)((unsigned short)i
) != i
) ||
2388 ( i
< 0 && (int)((short)i
) != i
) )
2389 parser_warning
("Integer constant out of 16bit range (%d), truncated to %d\n", i
, (short)i
);
2391 rd
= new_raw_data
();
2392 rd
->size
= sizeof
(short);
2393 rd
->data
= xmalloc
(rd
->size
);
2396 #ifdef WORDS_BIGENDIAN
2400 rd
->data
[0] = HIBYTE
(i
);
2401 rd
->data
[1] = LOBYTE
(i
);
2404 #ifndef WORDS_BIGENDIAN
2408 rd
->data
[1] = HIBYTE
(i
);
2409 rd
->data
[0] = LOBYTE
(i
);
2415 static raw_data_t
*long2raw_data
(int i
)
2418 rd
= new_raw_data
();
2419 rd
->size
= sizeof
(int);
2420 rd
->data
= xmalloc
(rd
->size
);
2423 #ifdef WORDS_BIGENDIAN
2427 rd
->data
[0] = HIBYTE
(HIWORD
(i
));
2428 rd
->data
[1] = LOBYTE
(HIWORD
(i
));
2429 rd
->data
[2] = HIBYTE
(LOWORD
(i
));
2430 rd
->data
[3] = LOBYTE
(LOWORD
(i
));
2433 #ifndef WORDS_BIGENDIAN
2437 rd
->data
[3] = HIBYTE
(HIWORD
(i
));
2438 rd
->data
[2] = LOBYTE
(HIWORD
(i
));
2439 rd
->data
[1] = HIBYTE
(LOWORD
(i
));
2440 rd
->data
[0] = LOBYTE
(LOWORD
(i
));
2446 static raw_data_t
*str2raw_data
(string_t
*str
)
2449 rd
= new_raw_data
();
2450 rd
->size
= str
->size
* (str
->type
== str_char ?
1 : 2);
2451 rd
->data
= xmalloc
(rd
->size
);
2452 if
(str
->type
== str_char
)
2453 memcpy
(rd
->data
, str
->str.cstr
, rd
->size
);
2454 else if
(str
->type
== str_unicode
)
2459 #ifdef WORDS_BIGENDIAN
2463 for
(i
= 0; i
< str
->size
; i
++)
2465 rd
->data
[2*i
+ 0] = HIBYTE
((WORD
)str
->str.wstr
[i
]);
2466 rd
->data
[2*i
+ 1] = LOBYTE
((WORD
)str
->str.wstr
[i
]);
2469 #ifndef WORDS_BIGENDIAN
2473 for
(i
= 0; i
< str
->size
; i
++)
2475 rd
->data
[2*i
+ 1] = HIBYTE
((WORD
)str
->str.wstr
[i
]);
2476 rd
->data
[2*i
+ 0] = LOBYTE
((WORD
)str
->str.wstr
[i
]);
2482 internal_error
(__FILE__
, __LINE__
, "Invalid stringtype\n");
2486 static raw_data_t
*merge_raw_data
(raw_data_t
*r1
, raw_data_t
*r2
)
2488 r1
->data
= xrealloc
(r1
->data
, r1
->size
+ r2
->size
);
2489 memcpy
(r1
->data
+ r1
->size
, r2
->data
, r2
->size
);
2490 r1
->size
+= r2
->size
;
2494 static raw_data_t
*merge_raw_data_int
(raw_data_t
*r1
, int i
)
2496 raw_data_t
*t
= int2raw_data
(i
);
2497 merge_raw_data
(r1
, t
);
2503 static raw_data_t
*merge_raw_data_long
(raw_data_t
*r1
, int i
)
2505 raw_data_t
*t
= long2raw_data
(i
);
2506 merge_raw_data
(r1
, t
);
2512 static raw_data_t
*merge_raw_data_str
(raw_data_t
*r1
, string_t
*str
)
2514 raw_data_t
*t
= str2raw_data
(str
);
2515 merge_raw_data
(r1
, t
);
2521 /* Function the go back in a list to get the head */
2522 static menu_item_t
*get_item_head
(menu_item_t
*p
)
2531 static menuex_item_t
*get_itemex_head
(menuex_item_t
*p
)
2540 static resource_t
*get_resource_head
(resource_t
*p
)
2549 static ver_block_t
*get_ver_block_head
(ver_block_t
*p
)
2558 static ver_value_t
*get_ver_value_head
(ver_value_t
*p
)
2567 static control_t
*get_control_head
(control_t
*p
)
2576 static event_t
*get_event_head
(event_t
*p
)
2585 /* Find a stringtable with given language */
2586 static stringtable_t
*find_stringtable
(lvc_t
*lvc
)
2590 assert
(lvc
!= NULL
);
2593 lvc
->language
= dup_language
(currentlanguage
);
2595 for
(stt
= sttres
; stt
; stt
= stt
->next
)
2597 if
(stt
->lvc.language
->id
== lvc
->language
->id
2598 && stt
->lvc.language
->sub
== lvc
->language
->sub
)
2600 /* Found a table with the same language */
2601 /* The version and characteristics are now handled
2602 * in the generation of the individual stringtables.
2603 * This enables localized analysis.
2604 if((stt->lvc.version && lvc->version && *(stt->lvc.version) != *(lvc->version))
2605 || (!stt->lvc.version && lvc->version)
2606 || (stt->lvc.version && !lvc->version))
2607 parser_warning("Stringtable's versions are not the same, using first definition\n");
2609 if((stt->lvc.characts && lvc->characts && *(stt->lvc.characts) != *(lvc->characts))
2610 || (!stt->lvc.characts && lvc->characts)
2611 || (stt->lvc.characts && !lvc->characts))
2612 parser_warning("Stringtable's characteristics are not the same, using first definition\n");
2620 /* qsort sorting function for string table entries */
2621 #define STE(p) ((const stt_entry_t *)(p))
2622 static int sort_stt_entry
(const void *e1
, const void *e2
)
2624 return STE
(e1
)->id
- STE
(e2
)->id
;
2628 static resource_t
*build_stt_resources
(stringtable_t
*stthead
)
2631 stringtable_t
*newstt
;
2633 resource_t
*rsclist
= NULL
;
2634 resource_t
*rsctail
= NULL
;
2639 characts_t
*characts
;
2645 /* For all languages defined */
2646 for
(stt
= stthead
; stt
; stt
= stt
->next
)
2648 assert
(stt
->nentries
> 0);
2650 /* Sort the entries */
2651 if
(stt
->nentries
> 1)
2652 qsort
(stt
->entries
, stt
->nentries
, sizeof
(stt
->entries
[0]), sort_stt_entry
);
2654 for
(i
= 0; i
< stt
->nentries
; )
2656 newstt
= new_stringtable
(&stt
->lvc
);
2657 newstt
->entries
= xmalloc
(16 * sizeof
(stt_entry_t
));
2658 memset
( newstt
->entries
, 0, 16 * sizeof
(stt_entry_t
) );
2659 newstt
->nentries
= 16;
2660 newstt
->idbase
= stt
->entries
[i
].id
& ~
0xf;
2661 for
(j
= 0; j
< 16 && i
< stt
->nentries
; j
++)
2663 if
(stt
->entries
[i
].id
- newstt
->idbase
== j
)
2665 newstt
->entries
[j
] = stt
->entries
[i
];
2673 /* Check individual memory options and get
2674 * the first characteristics/version
2676 for
(j
= 0; j
< 16; j
++)
2678 if
(!newstt
->entries
[j
].str
)
2680 andsum
&= newstt
->entries
[j
].memopt
;
2681 orsum |
= newstt
->entries
[j
].memopt
;
2683 characts
= newstt
->entries
[j
].characts
;
2685 version
= newstt
->entries
[j
].version
;
2689 warning
("Stringtable's memory options are not equal (idbase: %d)\n", newstt
->idbase
);
2691 /* Check version and characteristics */
2692 for
(j
= 0; j
< 16; j
++)
2695 && newstt
->entries
[j
].characts
2696 && *newstt
->entries
[j
].characts
!= *characts
)
2697 warning
("Stringtable's characteristics are not the same (idbase: %d)\n", newstt
->idbase
);
2699 && newstt
->entries
[j
].version
2700 && *newstt
->entries
[j
].version
!= *version
)
2701 warning
("Stringtable's versions are not the same (idbase: %d)\n", newstt
->idbase
);
2703 rsc
= new_resource
(res_stt
, newstt
, newstt
->memopt
, newstt
->lvc.language
);
2704 rsc
->name
= new_name_id
();
2705 rsc
->name
->type
= name_ord
;
2706 rsc
->name
->name.i_name
= (newstt
->idbase
>> 4) + 1;
2707 rsc
->memopt
= andsum
; /* Set to least common denominator */
2708 newstt
->memopt
= andsum
;
2709 newstt
->lvc.characts
= characts
;
2710 newstt
->lvc.version
= version
;
2718 rsctail
->next
= rsc
;
2719 rsc
->prev
= rsctail
;
2728 static toolbar_item_t
*ins_tlbr_button
(toolbar_item_t
*prev
, toolbar_item_t
*idrec
)
2737 static toolbar_item_t
*get_tlbr_buttons_head
(toolbar_item_t
*p
, int *nitems
)
2756 static string_t
*make_filename
(string_t
*str
)
2758 if
(str
->type
== str_char
)
2762 /* Remove escaped backslash and convert to forward */
2763 for
(cptr
= str
->str.cstr
; (cptr
= strchr
(cptr
, '\\')) != NULL
; cptr
++)
2767 memmove
(cptr
, cptr
+1, strlen
(cptr
));
2777 /* Remove escaped backslash and convert to forward */
2778 for
(wptr
= str
->str.wstr
; (wptr
= strchrW
(wptr
, '\\')) != NULL
; wptr
++)
2782 memmove
(wptr
, wptr
+1, strlenW
(wptr
));
2792 * Process all resources to extract fonts and build
2793 * a fontdir resource.
2795 * Note: MS' resource compiler (build 1472) does not
2796 * handle font resources with different languages.
2797 * The fontdir is generated in the last active language
2798 * and font identifiers must be unique across the entire
2800 * This is not logical considering the localization
2801 * constraints of all other resource types. MS has,
2802 * most probably, never testet localized fonts. However,
2803 * using fontresources is rare, so it might not occur
2804 * in normal applications.
2805 * Wine does require better localization because a lot
2806 * of languages are coded into the same executable.
2807 * Therefore, I will generate fontdirs for *each*
2808 * localized set of fonts.
2810 static resource_t
*build_fontdir
(resource_t
**fnt
, int nfnt
)
2812 static int once
= 0;
2815 warning
("Need to parse fonts, not yet implemented (fnt: %p, nfnt: %d)\n", fnt
, nfnt
);
2821 static resource_t
*build_fontdirs
(resource_t
*tail
)
2824 resource_t
*lst
= NULL
;
2825 resource_t
**fnt
= NULL
; /* List of all fonts */
2827 resource_t
**fnd
= NULL
; /* List of all fontdirs */
2829 resource_t
**lanfnt
= NULL
;
2836 nid.type
= name_str
;
2837 nid.name.s_name
= &str
;
2838 str.type
= str_char
;
2839 str.str.cstr
= xstrdup
("FONTDIR");
2842 /* Extract all fonts and fontdirs */
2843 for
(rsc
= tail
; rsc
; rsc
= rsc
->prev
)
2845 if
(rsc
->type
== res_fnt
)
2848 fnt
= xrealloc
(fnt
, nfnt
* sizeof
(*fnt
));
2851 else if
(rsc
->type
== res_fntdir
)
2854 fnd
= xrealloc
(fnd
, nfnd
* sizeof
(*fnd
));
2859 /* Verify the name of the present fontdirs */
2860 for
(i
= 0; i
< nfnd
; i
++)
2862 if
(compare_name_id
(&nid
, fnd
[i
]->name
))
2864 warning
("User supplied FONTDIR entry has an invalid name '%s', ignored\n",
2865 get_nameid_str
(fnd
[i
]->name
));
2874 warning
("Found %d FONTDIR entries without any fonts present\n", nfnd
);
2879 lanfnt
= xmalloc
(nfnt
* sizeof
(*lanfnt
));
2880 memset
( lanfnt
, 0, nfnt
* sizeof
(*lanfnt
));
2882 /* Get all fonts covered by fontdirs */
2883 for
(i
= 0; i
< nfnd
; i
++)
2891 for
(j
= 0; j
< nfnt
; j
++)
2895 if
(fnt
[j
]->lan
->id
== fnd
[i
]->lan
->id
&& fnt
[j
]->lan
->sub
== fnd
[i
]->lan
->sub
)
2897 lanfnt
[nlanfnt
] = fnt
[j
];
2903 cnt
= *(WORD
*)fnd
[i
]->res.fnd
->data
->data
;
2906 else if
(nlanfnt
== BYTESWAP_WORD
(cnt
))
2909 error("FONTDIR for language %d,%d has wrong count (%d, expected %d)\n",
2910 fnd
[i
]->lan
->id
, fnd
[i
]->lan
->sub
, cnt
, nlanfnt
);
2911 #ifdef WORDS_BIGENDIAN
2912 if
((byteorder
== WRC_BO_LITTLE
&& !isswapped
) ||
(byteorder
!= WRC_BO_LITTLE
&& isswapped
))
2914 if
((byteorder
== WRC_BO_BIG
&& !isswapped
) ||
(byteorder
!= WRC_BO_BIG
&& isswapped
))
2917 internal_error
(__FILE__
, __LINE__
, "User supplied FONTDIR needs byteswapping\n");
2921 /* We now have fonts left where we need to make a fontdir resource */
2922 for
(i
= fntleft
= 0; i
< nfnt
; i
++)
2929 /* Get fonts of same language in lanfnt[] */
2930 for
(i
= nlanfnt
= 0; i
< nfnt
; i
++)
2937 lanfnt
[nlanfnt
] = fnt
[i
];
2942 else if
(fnt
[i
]->lan
->id
== lanfnt
[0]->lan
->id
&& fnt
[i
]->lan
->sub
== lanfnt
[0]->lan
->sub
)
2946 /* and build a fontdir */
2947 rsc
= build_fontdir
(lanfnt
, nlanfnt
);
2968 * This gets invoked to determine whether the next resource
2969 * is to be of a standard-type (e.g. bitmaps etc.), or should
2970 * be a user-type resource. This function is required because
2971 * there is the _possibility_ of a lookahead token in the
2972 * parser, which is generated from the "expr" state in the
2975 * The general resource format is:
2976 * <identifier> <type> <flags> <resourcebody>
2978 * The <identifier> can either be tIDENT or "expr". The latter
2979 * will always generate a lookahead, which is the <type> of the
2980 * resource to parse. Otherwise, we need to get a new token from
2981 * the scanner to determine the next step.
2983 * The problem arrises when <type> is numerical. This case should
2984 * map onto default resource-types and be parsed as such instead
2985 * of being mapped onto user-type resources.
2987 * The trick lies in the fact that yacc (bison) doesn't care about
2988 * intermediate changes of the lookahead while reducing a rule. We
2989 * simply replace the lookahead with a token that will result in
2990 * a shift to the appropriate rule for the specific resource-type.
2992 static int rsrcid_to_token
(int lookahead
)
2995 const char *type
= "?";
2997 /* Get a token if we don't have one yet */
2998 if
(lookahead
== YYEMPTY
)
3001 /* Only numbers are possibly interesting */
3031 case WRC_RT_FONTDIR
:
3039 case WRC_RT_MESSAGETABLE
:
3040 type
= "MESSAGETABLE";
3041 token
= tMESSAGETABLE
;
3043 case WRC_RT_DLGINIT
:
3047 case WRC_RT_ACCELERATOR
:
3048 type
= "ACCELERATOR";
3049 token
= tACCELERATORS
;
3059 case WRC_RT_VERSION
:
3061 token
= tVERSIONINFO
;
3063 case WRC_RT_TOOLBAR
:
3073 type
= "STRINGTABLE";
3076 case WRC_RT_ANICURSOR
:
3077 case WRC_RT_ANIICON
:
3078 case WRC_RT_GROUP_CURSOR
:
3079 case WRC_RT_GROUP_ICON
:
3080 parser_warning
("Usertype uses reserved type ID %d, which is auto-generated\n", yylval.num
);
3083 case WRC_RT_DLGINCLUDE
:
3084 case WRC_RT_PLUGPLAY
:
3086 parser_warning
("Usertype uses reserved type ID %d, which is not supported by wrc yet\n", yylval.num
);