parser.y 74.7 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2
%{
/*
3 4 5
 * Copyright 1994	Martin von Loewis
 * Copyright 1998-2000	Bertho A. Stultiens (BS)
 *           1999	Juergen Schmied (JS)
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 *
7 8 9 10 11 12 13 14 15 16 17 18
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
20 21
 *
 * History:
22 23
 * 24-Jul-2000 BS	- Made a fix for broken Berkeley yacc on
 *			  non-terminals (see cjunk rule).
24 25
 * 21-May-2000 BS	- Partial implementation of font resources.
 *			- Corrected language propagation for binary
Andreas Mohr's avatar
Andreas Mohr committed
26
 *			  resources such as bitmaps, icons, cursors,
27 28 29 30 31 32
 *			  userres and rcdata. The language is now
 *			  correct in .res files.
 *			- Fixed reading the resource name as ident,
 *			  so that it may overlap keywords.
 * 20-May-2000 BS	- Implemented animated cursors and icons
 *			  resource types.
33 34 35 36
 * 30-Apr-2000 BS	- Reintegration into the wine-tree
 * 14-Jan-2000 BS	- Redid the usertype resources so that they
 *			  are compatible.
 * 02-Jan-2000 BS	- Removed the preprocessor from the grammar
37
 *			  except for the # command (line numbers).
38 39
 *
 * 06-Nov-1999 JS	- see CHANGES
40
 *
41
 * 29-Dec-1998 AdH	- Grammar and function extensions.
42
 *			     grammar: TOOLBAR resources, Named ICONs in
43
 *				DIALOGS
44
 *			     functions: semantic actions for the grammar
45 46 47 48
 *				changes, resource files can now be anywhere
 *				on the include path instead of just in the
 *				current directory
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
49 50 51 52 53 54
 * 20-Jun-1998 BS	- Fixed a bug in load_file() where the name was not
 *			  printed out correctly.
 *
 * 17-Jun-1998 BS	- Fixed a bug in CLASS statement parsing which should
 *			  also accept a tSTRING as argument.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
 * 25-May-1998 BS	- Found out that I need to support language, version
 *			  and characteristics in inline resources (bitmap,
 *			  cursor, etc) but they can also be specified with
 *			  a filename. This renders my filename-scanning scheme
 *			  worthless. Need to build newline parsing to solve
 *			  this one.
 *			  It will come with version 1.1.0 (sigh).
 *
 * 19-May-1998 BS	- Started to build a builtin preprocessor
 *
 * 30-Apr-1998 BS	- Redid the stringtable parsing/handling. My previous
 *			  ideas had some serious flaws.
 *
 * 27-Apr-1998 BS	- Removed a lot of dead comments and put it in a doc
 *			  file.
 *
 * 21-Apr-1998 BS	- Added correct behavior for cursors and icons.
 *			- This file is growing too big. It is time to strip
 *			  things and put it in a support file.
 *
 * 19-Apr-1998 BS	- Tagged the stringtable resource so that only one
 *			  resource will be created. This because the table
 *			  has a different layout than other resources. The
 *			  table has to be sorted, and divided into smaller
 *			  resource entries (see comment in source).
 *
 * 17-Apr-1998 BS	- Almost all strings, including identifiers, are parsed
 *			  as string_t which include unicode strings upon
 *			  input.
 *			- Parser now emits a warning when compiling win32
 *			  extensions in win16 mode.
 *
Francois Gouget's avatar
Francois Gouget committed
87
 * 16-Apr-1998 BS	- Raw data elements are now *optionally* separated
Alexandre Julliard's avatar
Alexandre Julliard committed
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
 *			  by commas. Read the comments in file sq2dq.l.
 *			- FIXME: there are instances in the source that rely
 *			  on the fact that int==32bit and pointers are int size.
 *			- Fixed the conflict in menuex by changing a rule
 *			  back into right recursion. See note in source.
 *			- UserType resources cannot have an expression as its
 *			  typeclass. See note in source.
 *
 * 15-Apr-1998 BS	- Changed all right recursion into left recursion to
 *			  get reduction of the parsestack.
 *			  This also helps communication between bison and flex.
 *			  Main advantage is that the Empty rule gets reduced
 *			  first, which is used to allocate/link things.
 *			  It also added a shift/reduce conflict in the menuex
 *			  handling, due to expression/option possibility,
 *			  although not serious.
 *
 * 14-Apr-1998 BS	- Redone almost the entire parser. We're not talking
 *			  about making it more efficient, but readable (for me)
 *			  and slightly easier to expand/change.
 *			  This is done primarily by using more reduce states
 *			  with many (intuitive) types for the various resource
 *			  statements.
 *			- Added expression handling for all resources where a
 *			  number is accepted (not only for win32). Also added
 *			  multiply and division (not MS compatible, but handy).
 *			  Unary minus introduced a shift/reduce conflict, but
 *			  it is not serious.
 *
 * 13-Apr-1998 BS	- Reordered a lot of things
 *			- Made the source more readable
 *			- Added Win32 resource definitions
 *			- Corrected syntax problems with an old yacc (;)
 *			- Added extra comment about grammar
 */
Patrik Stridvall's avatar
Patrik Stridvall committed
123
#include "config.h"
124
#include "wine/port.h"
Patrik Stridvall's avatar
Patrik Stridvall committed
125

Alexandre Julliard's avatar
Alexandre Julliard committed
126 127 128 129 130
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
131
#include <string.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
132 133 134 135 136

#include "wrc.h"
#include "utils.h"
#include "newstruc.h"
#include "dumpres.h"
137
#include "wine/wpp.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
138
#include "parser.h"
139
#include "windef.h"
140
#include "winbase.h"
141
#include "wingdi.h"
142
#include "winuser.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
143

144
int want_nl = 0;	/* Signal flex that we need the next newline */
145
int want_id = 0;	/* Signal flex that we need the next identifier */
146
static stringtable_t *tagstt;	/* Stringtable tag.
Alexandre Julliard's avatar
Alexandre Julliard committed
147 148 149 150
			 * It is set while parsing a stringtable to one of
			 * the stringtables in the sttres list or a new one
			 * if the language was not parsed before.
			 */
151
static stringtable_t *sttres;	/* Stringtable resources. This holds the list of
Alexandre Julliard's avatar
Alexandre Julliard committed
152 153
			 * stringtables with different lanuages
			 */
154 155
static int dont_want_id = 0;	/* See language parsing for details */

Alexandre Julliard's avatar
Alexandre Julliard committed
156 157 158 159 160
/* Set to the current options of the currently scanning stringtable */
static int *tagstt_memopt;
static characts_t *tagstt_characts;
static version_t *tagstt_version;

161 162
static const char riff[4] = "RIFF";	/* RIFF file magic for animated cursor/icon */

Alexandre Julliard's avatar
Alexandre Julliard committed
163
/* Prototypes of here defined functions */
164 165 166 167 168 169 170 171 172 173 174 175 176
static event_t *get_event_head(event_t *p);
static control_t *get_control_head(control_t *p);
static ver_value_t *get_ver_value_head(ver_value_t *p);
static ver_block_t *get_ver_block_head(ver_block_t *p);
static resource_t *get_resource_head(resource_t *p);
static menu_item_t *get_item_head(menu_item_t *p);
static raw_data_t *merge_raw_data_str(raw_data_t *r1, string_t *str);
static raw_data_t *merge_raw_data_int(raw_data_t *r1, int i);
static raw_data_t *merge_raw_data_long(raw_data_t *r1, int i);
static raw_data_t *merge_raw_data(raw_data_t *r1, raw_data_t *r2);
static raw_data_t *str2raw_data(string_t *str);
static raw_data_t *int2raw_data(int i);
static raw_data_t *long2raw_data(int i);
177
static raw_data_t *load_file(string_t *name, language_t *lang);
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
static itemex_opt_t *new_itemex_opt(int id, int type, int state, int helpid);
static event_t *add_string_event(string_t *key, int id, int flags, event_t *prev);
static event_t *add_event(int key, int id, int flags, event_t *prev);
static name_id_t *convert_ctlclass(name_id_t *cls);
static control_t *ins_ctrl(int type, int special_style, control_t *ctrl, control_t *prev);
static dialog_t *dialog_version(version_t *v, dialog_t *dlg);
static dialog_t *dialog_characteristics(characts_t *c, dialog_t *dlg);
static dialog_t *dialog_language(language_t *l, dialog_t *dlg);
static dialog_t *dialog_menu(name_id_t *m, dialog_t *dlg);
static dialog_t *dialog_class(name_id_t *n, dialog_t *dlg);
static dialog_t *dialog_font(font_id_t *f, dialog_t *dlg);
static dialog_t *dialog_caption(string_t *s, dialog_t *dlg);
static dialog_t *dialog_exstyle(style_t * st, dialog_t *dlg);
static dialog_t *dialog_style(style_t * st, dialog_t *dlg);
static resource_t *build_stt_resources(stringtable_t *stthead);
static stringtable_t *find_stringtable(lvc_t *lvc);
static toolbar_item_t *ins_tlbr_button(toolbar_item_t *prev, toolbar_item_t *idrec);
static toolbar_item_t *get_tlbr_buttons_head(toolbar_item_t *p, int *nitems);
static string_t *make_filename(string_t *s);
197 198
static resource_t *build_fontdirs(resource_t *tail);
static resource_t *build_fontdir(resource_t **fnt, int nfnt);
199
static int rsrcid_to_token(int lookahead);
Alexandre Julliard's avatar
Alexandre Julliard committed
200 201 202 203 204 205

%}
%union{
	string_t	*str;
	int		num;
	int		*iptr;
206
	char		*cptr;
Alexandre Julliard's avatar
Alexandre Julliard committed
207 208 209 210 211
	resource_t	*res;
	accelerator_t	*acc;
	bitmap_t	*bmp;
	dialog_t	*dlg;
	font_t		*fnt;
212
	fontdir_t	*fnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
213
	menu_t		*men;
214
	html_t		*html;
Alexandre Julliard's avatar
Alexandre Julliard committed
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	rcdata_t	*rdt;
	stringtable_t	*stt;
	stt_entry_t	*stte;
	user_t		*usr;
	messagetable_t	*msg;
	versioninfo_t	*veri;
	control_t	*ctl;
	name_id_t	*nid;
	font_id_t	*fntid;
	language_t	*lan;
	version_t	*ver;
	characts_t	*chars;
	event_t		*event;
	menu_item_t	*menitm;
	itemex_opt_t	*exopt;
	raw_data_t	*raw;
	lvc_t		*lvc;
	ver_value_t	*val;
	ver_block_t	*blk;
	ver_words_t	*verw;
235 236
	toolbar_t	*tlbar;
	toolbar_item_t	*tlbarItems;
237 238
	dlginit_t       *dginit;
	style_pair_t	*styles;
239
	style_t		*style;
240
	ani_any_t	*ani;
Alexandre Julliard's avatar
Alexandre Julliard committed
241 242
}

243
%token tNL
244
%token <num> tNUMBER tLNUMBER
245
%token <str> tSTRING tIDENT
246 247
%token <raw> tRAWDATA
%token tACCELERATORS tBITMAP tCURSOR tDIALOG tDIALOGEX tMENU tMENUEX tMESSAGETABLE
248
%token tRCDATA tVERSIONINFO tSTRINGTABLE tFONT tFONTDIR tICON tHTML
249 250 251 252 253 254 255 256 257 258 259 260 261
%token tAUTO3STATE tAUTOCHECKBOX tAUTORADIOBUTTON tCHECKBOX tDEFPUSHBUTTON
%token tPUSHBUTTON tRADIOBUTTON tSTATE3 /* PUSHBOX */
%token tGROUPBOX tCOMBOBOX tLISTBOX tSCROLLBAR
%token tCONTROL tEDITTEXT
%token tRTEXT tCTEXT tLTEXT
%token tBLOCK tVALUE
%token tSHIFT tALT tASCII tVIRTKEY tGRAYED tCHECKED tINACTIVE tNOINVERT
%token tPURE tIMPURE tDISCARDABLE tLOADONCALL tPRELOAD tFIXED tMOVEABLE
%token tCLASS tCAPTION tCHARACTERISTICS tEXSTYLE tSTYLE tVERSION tLANGUAGE
%token tFILEVERSION tPRODUCTVERSION tFILEFLAGSMASK tFILEOS tFILETYPE tFILEFLAGS tFILESUBTYPE
%token tMENUBARBREAK tMENUBREAK tMENUITEM tPOPUP tSEPARATOR
%token tHELP
%token tTOOLBAR tBUTTON
Alexandre Julliard's avatar
Alexandre Julliard committed
262
%token tBEGIN tEND
263
%token tDLGINIT
Alexandre Julliard's avatar
Alexandre Julliard committed
264 265 266 267 268
%left '|'
%left '^'
%left '&'
%left '+' '-'
%left '*' '/'
269 270
%right '~' tNOT
%left pUPM
Alexandre Julliard's avatar
Alexandre Julliard committed
271 272 273 274

%type <res> 	resource_file resource resources resource_definition
%type <stt>	stringtable strings
%type <fnt>	font
275
%type <fnd>	fontdir
Alexandre Julliard's avatar
Alexandre Julliard committed
276 277 278
%type <acc> 	accelerators
%type <event> 	events
%type <bmp> 	bitmap
279
%type <ani> 	cursor icon
280
%type <dlg> 	dialog dlg_attributes dialogex dlgex_attribs
Alexandre Julliard's avatar
Alexandre Julliard committed
281
%type <ctl> 	ctrls gen_ctrl lab_ctrl ctrl_desc iconinfo
282
%type <iptr>	helpid
Alexandre Julliard's avatar
Alexandre Julliard committed
283
%type <ctl>	exctrls gen_exctrl lab_exctrl exctrl_desc
284
%type <html>	html
Alexandre Julliard's avatar
Alexandre Julliard committed
285
%type <rdt> 	rcdata
286
%type <raw>	raw_data raw_elements opt_data file_raw
Alexandre Julliard's avatar
Alexandre Julliard committed
287 288 289 290
%type <veri> 	versioninfo fix_version
%type <verw>	ver_words
%type <blk>	ver_blocks ver_block
%type <val>	ver_values ver_value
291
%type <men> 	menu menuex
292
%type <menitm>	item_definitions menu_body itemex_definitions menuex_body
Alexandre Julliard's avatar
Alexandre Julliard committed
293 294 295 296
%type <exopt>	itemex_p_options itemex_options
%type <msg> 	messagetable
%type <usr> 	userres
%type <num> 	item_options
Alexandre Julliard's avatar
Alexandre Julliard committed
297
%type <nid> 	nameid nameid_s ctlclass usertype
298
%type <num> 	acc_opt acc accs
Alexandre Julliard's avatar
Alexandre Julliard committed
299
%type <iptr>	loadmemopts lamo lama
300
%type <fntid>	opt_font opt_exfont opt_expr
Alexandre Julliard's avatar
Alexandre Julliard committed
301 302 303 304
%type <lvc>	opt_lvc
%type <lan>	opt_language
%type <chars>	opt_characts
%type <ver>	opt_version
305
%type <num>	expr xpr
Alexandre Julliard's avatar
Alexandre Julliard committed
306
%type <iptr>	e_expr
307 308
%type <tlbar>	toolbar
%type <tlbarItems>	toolbar_items
309
%type <dginit>  dlginit
310
%type <styles>  optional_style_pair
311
%type <num>	any_num
312
%type <style>   style
313
%type <str>	filename
Alexandre Julliard's avatar
Alexandre Julliard committed
314 315 316 317 318

%%

resource_file
	: resources {
319
		resource_t *rsc, *head;
Alexandre Julliard's avatar
Alexandre Julliard committed
320 321 322 323 324 325 326 327 328
		/* First add stringtables to the resource-list */
		rsc = build_stt_resources(sttres);
		/* 'build_stt_resources' returns a head and $1 is a tail */
		if($1)
		{
			$1->next = rsc;
			if(rsc)
				rsc->prev = $1;
		}
329 330 331 332 333 334 335 336 337 338 339 340 341 342
		else
			$1 = rsc;
		/* Find the tail again */
		while($1 && $1->next)
			$1 = $1->next;
		/* Now add any fontdirecory */
		rsc = build_fontdirs($1);
		/* 'build_fontdir' returns a head and $1 is a tail */
		if($1)
		{
			$1->next = rsc;
			if(rsc)
				rsc->prev = $1;
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
343 344
		else
			$1 = rsc;
345

346
		/* Final statements before we're done */
347
                if ((head = get_resource_head($1)) != NULL)
348
                {
349 350 351 352 353 354 355 356
                    if (resource_top)  /* append to existing resources */
                    {
                        resource_t *tail = resource_top;
                        while (tail->next) tail = tail->next;
                        tail->next = head;
                        head->prev = tail;
                    }
                    else resource_top = head;
357 358
                }
                sttres = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
359 360 361 362 363
		}
	;

/* Resources are put into a linked list */
resources
364
	: /* Empty */		{ $$ = NULL; want_id = 1; }
Alexandre Julliard's avatar
Alexandre Julliard committed
365 366 367 368 369 370 371 372 373 374 375 376 377
	| resources resource	{
		if($2)
		{
			resource_t *tail = $2;
			resource_t *head = $2;
			while(tail->next)
				tail = tail->next;
			while(head->prev)
				head = head->prev;
			head->prev = $1;
			if($1)
				$1->next = head;
			$$ = tail;
378 379 380 381 382 383 384 385 386
			/* Check for duplicate identifiers */
			while($1 && head)
			{
				resource_t *rsc = $1;
				while(rsc)
				{
					if(rsc->type == head->type
					&& rsc->lan->id == head->lan->id
					&& rsc->lan->sub == head->lan->sub
387 388
					&& !compare_name_id(rsc->name, head->name)
					&& (rsc->type != res_usr || !compare_name_id(rsc->res.usr->type,head->res.usr->type)))
389
					{
390
						yyerror("Duplicate resource name '%s'", get_nameid_str(rsc->name));
391 392 393 394 395
					}
					rsc = rsc->prev;
				}
				head = head->next;
			}
Alexandre Julliard's avatar
Alexandre Julliard committed
396 397 398 399 400 401 402 403 404 405 406
		}
		else if($1)
		{
			resource_t *tail = $1;
			while(tail->next)
				tail = tail->next;
			$$ = tail;
		}
		else
			$$ = NULL;

407 408 409
		if(!dont_want_id)	/* See comments in language parsing below */
			want_id = 1;
		dont_want_id = 0;
410
		}
411 412
	/*
	 * The following newline rule will never get reduced because we never
413
	 * get the tNL token, unless we explicitly set the 'want_nl'
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
	 * flag, which we don't.
	 * The *ONLY* reason for this to be here is because Berkeley
	 * yacc (byacc), at least version 1.9, has a bug.
	 * (identified in the generated parser on the second
	 *  line with:
	 *  static char yysccsid[] = "@(#)yaccpar   1.9 (Berkeley) 02/21/93";
	 * )
	 * This extra rule fixes it.
	 * The problem is that the expression handling rule "expr: xpr"
	 * is not reduced on non-terminal tokens, defined above in the
	 * %token declarations. Token tNL is the only non-terminal that
	 * can occur. The error becomes visible in the language parsing
	 * rule below, which looks at the look-ahead token and tests it
	 * for tNL. However, byacc already generates an error upon reading
	 * the token instead of keeping it as a lookahead. The reason
	 * lies in the lack of a $default transition in the "expr : xpr . "
430
	 * state (currently state 25). It is probably omitted because tNL
431 432 433 434 435 436
	 * is a non-terminal and the state contains 2 s/r conflicts. The
	 * state enumerates all possible transitions instead of using a
	 * $default transition.
	 * All in all, it is a bug in byacc. (period)
	 */
	| resources tNL
437 438
	;

Alexandre Julliard's avatar
Alexandre Julliard committed
439 440 441

/* Parse top level resource definitions etc. */
resource
442
	: expr usrcvt resource_definition {
443
		$$ = $3;
Alexandre Julliard's avatar
Alexandre Julliard committed
444 445
		if($$)
		{
446
			if($1 > 65535 || $1 < -32768)
447
				yyerror("Resource's ID out of range (%d)", $1);
448 449 450
			$$->name = new_name_id();
			$$->name->type = name_ord;
			$$->name->name.i_name = $1;
451
			chat("Got %s (%d)\n", get_typename($3), $$->name->name.i_name);
Alexandre Julliard's avatar
Alexandre Julliard committed
452 453
			}
			}
454 455 456 457 458 459 460
	| tIDENT usrcvt resource_definition {
		$$ = $3;
		if($$)
		{
			$$->name = new_name_id();
			$$->name->type = name_str;
			$$->name->name.s_name = $1;
461
			chat("Got %s (%s)\n", get_typename($3), $$->name->name.s_name->str.cstr);
Alexandre Julliard's avatar
Alexandre Julliard committed
462 463 464 465 466 467 468 469
		}
		}
	| stringtable {
		/* Don't do anything, stringtables are converted to
		 * resource_t structures when we are finished parsing and
		 * the final rule of the parser is reduced (see above)
		 */
		$$ = NULL;
470
		chat("Got STRINGTABLE\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
471
		}
472
	| tLANGUAGE {want_nl = 1; } expr ',' expr {
473 474 475
		/* We *NEED* the newline to delimit the expression.
		 * Otherwise, we would not be able to set the next
		 * want_id anymore because of the token-lookahead.
476 477 478 479
		 *
		 * However, we can test the lookahead-token for
		 * being "non-expression" type, in which case we
		 * continue. Fortunately, tNL is the only token that
480
		 * will break expression parsing and is implicitly
481 482 483 484 485 486 487
		 * void, so we just remove it. This scheme makes it
		 * possible to do some (not all) fancy preprocessor
		 * stuff.
		 * BTW, we also need to make sure that the next
		 * reduction of 'resources' above will *not* set
		 * want_id because we already have a lookahead that
		 * cannot be undone.
488
		 */
489 490 491 492
		if(yychar != YYEMPTY && yychar != tNL)
			dont_want_id = 1;

		if(yychar == tNL)
493 494
			yychar = YYEMPTY;	/* Could use 'yyclearin', but we already need the*/
						/* direct access to yychar in rule 'usrcvt' below. */
495
		else if(yychar == tIDENT)
496
			parser_warning("LANGUAGE statement not delimited with newline; next identifier might be wrong\n");
497 498 499

		want_nl = 0;	/* We don't want it anymore if we didn't get it */

Alexandre Julliard's avatar
Alexandre Julliard committed
500
		if(!win32)
501
			parser_warning("LANGUAGE not supported in 16-bit mode\n");
502
		free(currentlanguage);
503
		if (get_language_codepage($3, $5) == -1)
504
			yyerror( "Language %04x is not supported", ($5<<10) + $3);
505
		currentlanguage = new_language($3, $5);
Alexandre Julliard's avatar
Alexandre Julliard committed
506
		$$ = NULL;
507
		chat("Got LANGUAGE %d,%d (0x%04x)\n", $3, $5, ($5<<10) + $3);
Alexandre Julliard's avatar
Alexandre Julliard committed
508 509 510
		}
	;

511 512 513 514 515 516 517
/*
 * Remapping of numerical resource types
 * (see also comment of called function below)
 */
usrcvt	: /* Empty */	{ yychar = rsrcid_to_token(yychar); }
	;

Alexandre Julliard's avatar
Alexandre Julliard committed
518 519
/*
 * Get a valid name/id
Alexandre Julliard's avatar
Alexandre Julliard committed
520 521
 */
nameid	: expr	{
522
		if($1 > 65535 || $1 < -32768)
523
			yyerror("Resource's ID out of range (%d)", $1);
Alexandre Julliard's avatar
Alexandre Julliard committed
524 525 526 527
		$$ = new_name_id();
		$$->type = name_ord;
		$$->name.i_name = $1;
		}
528
	| tIDENT {
Alexandre Julliard's avatar
Alexandre Julliard committed
529 530 531 532 533 534
		$$ = new_name_id();
		$$->type = name_str;
		$$->name.s_name = $1;
		}
	;

Alexandre Julliard's avatar
Alexandre Julliard committed
535 536 537 538 539 540 541 542 543 544 545
/*
 * Extra string recognition for CLASS statement in dialogs
 */
nameid_s: nameid	{ $$ = $1; }
	| tSTRING	{
		$$ = new_name_id();
		$$->type = name_str;
		$$->name.s_name = $1;
		}
	;

Alexandre Julliard's avatar
Alexandre Julliard committed
546 547 548
/* get the value for a single resource*/
resource_definition
	: accelerators	{ $$ = new_resource(res_acc, $1, $1->memopt, $1->lvc.language); }
549
	| bitmap	{ $$ = new_resource(res_bmp, $1, $1->memopt, $1->data->lvc.language); }
Alexandre Julliard's avatar
Alexandre Julliard committed
550 551
	| cursor {
		resource_t *rsc;
552
		if($1->type == res_anicur)
Alexandre Julliard's avatar
Alexandre Julliard committed
553
		{
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
			$$ = rsc = new_resource(res_anicur, $1->u.ani, $1->u.ani->memopt, $1->u.ani->data->lvc.language);
		}
		else if($1->type == res_curg)
		{
			cursor_t *cur;
			$$ = rsc = new_resource(res_curg, $1->u.curg, $1->u.curg->memopt, $1->u.curg->lvc.language);
			for(cur = $1->u.curg->cursorlist; cur; cur = cur->next)
			{
				rsc->prev = new_resource(res_cur, cur, $1->u.curg->memopt, $1->u.curg->lvc.language);
				rsc->prev->next = rsc;
				rsc = rsc->prev;
				rsc->name = new_name_id();
				rsc->name->type = name_ord;
				rsc->name->name.i_name = cur->id;
			}
Alexandre Julliard's avatar
Alexandre Julliard committed
569
		}
570
		else
571
			internal_error(__FILE__, __LINE__, "Invalid top-level type %d in cursor resource\n", $1->type);
572
		free($1);
Alexandre Julliard's avatar
Alexandre Julliard committed
573 574 575 576
		}
	| dialog	{ $$ = new_resource(res_dlg, $1, $1->memopt, $1->lvc.language); }
	| dialogex {
		if(win32)
577
			$$ = new_resource(res_dlg, $1, $1->memopt, $1->lvc.language);
Alexandre Julliard's avatar
Alexandre Julliard committed
578 579 580
		else
			$$ = NULL;
		}
581 582 583
	| dlginit	{ $$ = new_resource(res_dlginit, $1, $1->memopt, $1->data->lvc.language); }
	| font		{ $$ = new_resource(res_fnt, $1, $1->memopt, $1->data->lvc.language); }
	| fontdir	{ $$ = new_resource(res_fntdir, $1, $1->memopt, $1->data->lvc.language); }
Alexandre Julliard's avatar
Alexandre Julliard committed
584 585
	| icon {
		resource_t *rsc;
586
		if($1->type == res_aniico)
Alexandre Julliard's avatar
Alexandre Julliard committed
587
		{
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
			$$ = rsc = new_resource(res_aniico, $1->u.ani, $1->u.ani->memopt, $1->u.ani->data->lvc.language);
		}
		else if($1->type == res_icog)
		{
			icon_t *ico;
			$$ = rsc = new_resource(res_icog, $1->u.icog, $1->u.icog->memopt, $1->u.icog->lvc.language);
			for(ico = $1->u.icog->iconlist; ico; ico = ico->next)
			{
				rsc->prev = new_resource(res_ico, ico, $1->u.icog->memopt, $1->u.icog->lvc.language);
				rsc->prev->next = rsc;
				rsc = rsc->prev;
				rsc->name = new_name_id();
				rsc->name->type = name_ord;
				rsc->name->name.i_name = ico->id;
			}
Alexandre Julliard's avatar
Alexandre Julliard committed
603
		}
604
		else
605
			internal_error(__FILE__, __LINE__, "Invalid top-level type %d in icon resource\n", $1->type);
606
		free($1);
Alexandre Julliard's avatar
Alexandre Julliard committed
607 608 609 610
		}
	| menu		{ $$ = new_resource(res_men, $1, $1->memopt, $1->lvc.language); }
	| menuex {
		if(win32)
611
			$$ = new_resource(res_men, $1, $1->memopt, $1->lvc.language);
Alexandre Julliard's avatar
Alexandre Julliard committed
612 613 614
		else
			$$ = NULL;
		}
615
	| messagetable	{ $$ = new_resource(res_msg, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, $1->data->lvc.language); }
616
	| html		{ $$ = new_resource(res_html, $1, $1->memopt, $1->data->lvc.language); }
617
	| rcdata	{ $$ = new_resource(res_rdt, $1, $1->memopt, $1->data->lvc.language); }
618
	| toolbar	{ $$ = new_resource(res_toolbar, $1, $1->memopt, $1->lvc.language); }
619 620
	| userres	{ $$ = new_resource(res_usr, $1, $1->memopt, $1->data->lvc.language); }
	| versioninfo	{ $$ = new_resource(res_ver, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, $1->lvc.language); }
Alexandre Julliard's avatar
Alexandre Julliard committed
621 622
	;

623

624
filename: tIDENT	{ $$ = make_filename($1); }
625 626 627
	| tSTRING	{ $$ = make_filename($1); }
	;

Alexandre Julliard's avatar
Alexandre Julliard committed
628
/* ------------------------------ Bitmap ------------------------------ */
629
bitmap	: tBITMAP loadmemopts file_raw	{ $$ = new_bitmap($3, $2); }
Alexandre Julliard's avatar
Alexandre Julliard committed
630 631 632
	;

/* ------------------------------ Cursor ------------------------------ */
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
cursor	: tCURSOR loadmemopts file_raw	{
		$$ = new_ani_any();
		if($3->size > 4 && !memcmp($3->data, riff, sizeof(riff)))
		{
			$$->type = res_anicur;
			$$->u.ani = new_ani_curico(res_anicur, $3, $2);
		}
		else
		{
			$$->type = res_curg;
			$$->u.curg = new_cursor_group($3, $2);
		}
	}
	;

/* ------------------------------ Icon ------------------------------ */
icon	: tICON loadmemopts file_raw	{
		$$ = new_ani_any();
		if($3->size > 4 && !memcmp($3->data, riff, sizeof(riff)))
		{
			$$->type = res_aniico;
			$$->u.ani = new_ani_curico(res_aniico, $3, $2);
		}
		else
		{
			$$->type = res_icog;
			$$->u.icog = new_icon_group($3, $2);
		}
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
662 663 664
	;

/* ------------------------------ Font ------------------------------ */
665 666 667 668 669 670 671
	/*
	 * The reading of raw_data for fonts is a Borland BRC
	 * extension. MS generates an error. However, it is
	 * most logical to support this, considering how wine
	 * enters things in CVS (ascii).
	 */
font	: tFONT loadmemopts file_raw	{ $$ = new_font($3, $2); }
Alexandre Julliard's avatar
Alexandre Julliard committed
672 673
	;

674 675 676 677 678 679 680
	/*
	 * The fontdir is a Borland BRC extension which only
	 * reads the data as 'raw_data' from the file.
	 * I don't know whether it is interpreted.
	 * The fontdir is generated if it was not present and
	 * fonts are defined in the source.
	 */
681
fontdir	: tFONTDIR loadmemopts file_raw	{ $$ = new_fontdir($3, $2); }
Alexandre Julliard's avatar
Alexandre Julliard committed
682 683 684 685 686 687 688
	;

/* ------------------------------ MessageTable ------------------------------ */
/* It might be interesting to implement the MS Message compiler here as well
 * to get everything in one source. Might be a future project.
 */
messagetable
689
	: tMESSAGETABLE loadmemopts file_raw	{
Alexandre Julliard's avatar
Alexandre Julliard committed
690
		if(!win32)
691
			parser_warning("MESSAGETABLE not supported in 16-bit mode\n");
692
		$$ = new_messagetable($3, $2);
Alexandre Julliard's avatar
Alexandre Julliard committed
693 694 695
		}
	;

696 697 698 699
/* ------------------------------ HTML ------------------------------ */
html	: tHTML loadmemopts file_raw	{ $$ = new_html($3, $2); }
	;

Alexandre Julliard's avatar
Alexandre Julliard committed
700
/* ------------------------------ RCData ------------------------------ */
701
rcdata	: tRCDATA loadmemopts file_raw	{ $$ = new_rcdata($3, $2); }
Alexandre Julliard's avatar
Alexandre Julliard committed
702 703
	;

704
/* ------------------------------ DLGINIT ------------------------------ */
705
dlginit	: tDLGINIT loadmemopts file_raw	{ $$ = new_dlginit($3, $2); }
706
	;
707

Alexandre Julliard's avatar
Alexandre Julliard committed
708
/* ------------------------------ UserType ------------------------------ */
709
userres	: usertype loadmemopts file_raw		{
710
#ifdef WORDS_BIGENDIAN
711
			if(pedantic && byteorder != WRC_BO_LITTLE)
712
#else
713
			if(pedantic && byteorder == WRC_BO_BIG)
714
#endif
715
				parser_warning("Byteordering is not little-endian and type cannot be interpreted\n");
716 717
			$$ = new_user($1, $3, $2);
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
718 719
	;

720
usertype: tNUMBER {
Alexandre Julliard's avatar
Alexandre Julliard committed
721 722 723 724
		$$ = new_name_id();
		$$->type = name_ord;
		$$->name.i_name = $1;
		}
725
	| tIDENT {
Alexandre Julliard's avatar
Alexandre Julliard committed
726 727 728 729 730 731 732 733
		$$ = new_name_id();
		$$->type = name_str;
		$$->name.s_name = $1;
		}
	;

/* ------------------------------ Accelerator ------------------------------ */
accelerators
734
	: tACCELERATORS loadmemopts opt_lvc tBEGIN events tEND {
Alexandre Julliard's avatar
Alexandre Julliard committed
735 736 737 738 739 740 741 742 743 744 745
		$$ = new_accelerator();
		if($2)
		{
			$$->memopt = *($2);
			free($2);
		}
		else
		{
			$$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
		}
		if(!$5)
746
			yyerror("Accelerator table must have at least one entry");
Alexandre Julliard's avatar
Alexandre Julliard committed
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
		$$->events = get_event_head($5);
		if($3)
		{
			$$->lvc = *($3);
			free($3);
		}
		if(!$$->lvc.language)
			$$->lvc.language = dup_language(currentlanguage);
		}
	;

events	: /* Empty */ 				{ $$=NULL; }
	| events tSTRING ',' expr acc_opt	{ $$=add_string_event($2, $4, $5, $1); }
	| events expr ',' expr acc_opt		{ $$=add_event($2, $4, $5, $1); }
	;

763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
/*
 * The empty rule generates a s/r conflict because of {bi,u}nary expr
 * on - and +. It cannot be solved in any way because it is the same as
 * the if/then/else problem (LALR(1) problem). The conflict is moved
 * away by forcing it to be in the expression handling below.
 */
acc_opt	: /* Empty */	{ $$ = 0; }
	| ',' accs	{ $$ = $2; }
	;

accs	: acc		{ $$ = $1; }
	| accs ',' acc	{ $$ = $1 | $3; }
	;

acc	: tNOINVERT 	{ $$ = WRC_AF_NOINVERT; }
	| tSHIFT	{ $$ = WRC_AF_SHIFT; }
	| tCONTROL	{ $$ = WRC_AF_CONTROL; }
	| tALT		{ $$ = WRC_AF_ALT; }
	| tASCII	{ $$ = WRC_AF_ASCII; }
	| tVIRTKEY	{ $$ = WRC_AF_VIRTKEY; }
Alexandre Julliard's avatar
Alexandre Julliard committed
783 784 785 786
	;

/* ------------------------------ Dialog ------------------------------ */
/* FIXME: Support EXSTYLE in the dialog line itself */
787
dialog	: tDIALOG loadmemopts expr ',' expr ',' expr ',' expr dlg_attributes
Alexandre Julliard's avatar
Alexandre Julliard committed
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
	  tBEGIN  ctrls tEND {
		if($2)
		{
			$10->memopt = *($2);
			free($2);
		}
		else
			$10->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
		$10->x = $3;
		$10->y = $5;
		$10->width = $7;
		$10->height = $9;
		$10->controls = get_control_head($12);
		$$ = $10;
		if(!$$->gotstyle)
		{
804
			$$->style = new_style(0,0);
805
			$$->style->or_mask = WS_POPUP;
Alexandre Julliard's avatar
Alexandre Julliard committed
806 807 808
			$$->gotstyle = TRUE;
		}
		if($$->title)
809
			$$->style->or_mask |= WS_CAPTION;
Alexandre Julliard's avatar
Alexandre Julliard committed
810
		if($$->font)
811 812 813 814 815
			$$->style->or_mask |= DS_SETFONT;

		$$->style->or_mask &= ~($$->style->and_mask);
		$$->style->and_mask = 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
816 817 818 819 820 821
		if(!$$->lvc.language)
			$$->lvc.language = dup_language(currentlanguage);
		}
	;

dlg_attributes
822 823 824 825 826 827 828 829 830 831
	: /* Empty */				{ $$=new_dialog(); }
	| dlg_attributes tSTYLE style		{ $$=dialog_style($3,$1); }
	| dlg_attributes tEXSTYLE style		{ $$=dialog_exstyle($3,$1); }
	| dlg_attributes tCAPTION tSTRING	{ $$=dialog_caption($3,$1); }
	| dlg_attributes opt_font		{ $$=dialog_font($2,$1); }
	| dlg_attributes tCLASS nameid_s	{ $$=dialog_class($3,$1); }
	| dlg_attributes tMENU nameid		{ $$=dialog_menu($3,$1); }
	| dlg_attributes opt_language		{ $$=dialog_language($2,$1); }
	| dlg_attributes opt_characts		{ $$=dialog_characteristics($2,$1); }
	| dlg_attributes opt_version		{ $$=dialog_version($2,$1); }
Alexandre Julliard's avatar
Alexandre Julliard committed
832 833 834
	;

ctrls	: /* Empty */				{ $$ = NULL; }
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
	| ctrls tCONTROL	gen_ctrl	{ $$=ins_ctrl(-1, 0, $3, $1); }
	| ctrls tEDITTEXT	ctrl_desc	{ $$=ins_ctrl(CT_EDIT, 0, $3, $1); }
	| ctrls tLISTBOX	ctrl_desc	{ $$=ins_ctrl(CT_LISTBOX, 0, $3, $1); }
	| ctrls tCOMBOBOX	ctrl_desc	{ $$=ins_ctrl(CT_COMBOBOX, 0, $3, $1); }
	| ctrls tSCROLLBAR	ctrl_desc	{ $$=ins_ctrl(CT_SCROLLBAR, 0, $3, $1); }
	| ctrls tCHECKBOX	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_CHECKBOX, $3, $1); }
	| ctrls tDEFPUSHBUTTON	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_DEFPUSHBUTTON, $3, $1); }
	| ctrls tGROUPBOX	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_GROUPBOX, $3, $1);}
	| ctrls tPUSHBUTTON	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_PUSHBUTTON, $3, $1); }
/*	| ctrls tPUSHBOX	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
	| ctrls tRADIOBUTTON	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_RADIOBUTTON, $3, $1); }
	| ctrls tAUTO3STATE	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTO3STATE, $3, $1); }
	| ctrls tSTATE3		lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_3STATE, $3, $1); }
	| ctrls tAUTOCHECKBOX	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTOCHECKBOX, $3, $1); }
	| ctrls tAUTORADIOBUTTON lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTORADIOBUTTON, $3, $1); }
	| ctrls tLTEXT		lab_ctrl	{ $$=ins_ctrl(CT_STATIC, SS_LEFT, $3, $1); }
	| ctrls tCTEXT		lab_ctrl	{ $$=ins_ctrl(CT_STATIC, SS_CENTER, $3, $1); }
	| ctrls tRTEXT		lab_ctrl	{ $$=ins_ctrl(CT_STATIC, SS_RIGHT, $3, $1); }
Alexandre Julliard's avatar
Alexandre Julliard committed
853
	/* special treatment for icons, as the extent is optional */
854
	| ctrls tICON nameid_s opt_comma expr ',' expr ',' expr iconinfo {
855
		$10->title = $3;
Alexandre Julliard's avatar
Alexandre Julliard committed
856 857 858 859 860 861 862 863
		$10->id = $5;
		$10->x = $7;
		$10->y = $9;
		$$ = ins_ctrl(CT_STATIC, SS_ICON, $10, $1);
		}
	;

lab_ctrl
864
	: nameid_s opt_comma expr ',' expr ',' expr ',' expr ',' expr optional_style_pair {
Alexandre Julliard's avatar
Alexandre Julliard committed
865
		$$=new_control();
866
		$$->title = $1;
Alexandre Julliard's avatar
Alexandre Julliard committed
867 868 869 870 871 872 873
		$$->id = $3;
		$$->x = $5;
		$$->y = $7;
		$$->width = $9;
		$$->height = $11;
		if($12)
		{
874
			$$->style = $12->style;
Alexandre Julliard's avatar
Alexandre Julliard committed
875
			$$->gotstyle = TRUE;
876 877 878 879 880 881
			if ($12->exstyle)
			{
			    $$->exstyle = $12->exstyle;
			    $$->gotexstyle = TRUE;
			}
			free($12);
Alexandre Julliard's avatar
Alexandre Julliard committed
882 883 884 885 886
		}
		}
	;

ctrl_desc
887
	: expr ',' expr ',' expr ',' expr ',' expr optional_style_pair {
Alexandre Julliard's avatar
Alexandre Julliard committed
888 889 890 891 892 893 894 895
		$$ = new_control();
		$$->id = $1;
		$$->x = $3;
		$$->y = $5;
		$$->width = $7;
		$$->height = $9;
		if($10)
		{
896
			$$->style = $10->style;
Alexandre Julliard's avatar
Alexandre Julliard committed
897
			$$->gotstyle = TRUE;
898 899 900 901 902 903
			if ($10->exstyle)
			{
			    $$->exstyle = $10->exstyle;
			    $$->gotexstyle = TRUE;
			}
			free($10);
Alexandre Julliard's avatar
Alexandre Julliard committed
904 905 906 907 908 909 910 911 912 913 914 915
		}
		}
	;

iconinfo: /* Empty */
		{ $$ = new_control(); }

	| ',' expr ',' expr {
		$$ = new_control();
		$$->width = $2;
		$$->height = $4;
		}
916
	| ',' expr ',' expr ',' style {
Alexandre Julliard's avatar
Alexandre Julliard committed
917 918 919 920 921 922
		$$ = new_control();
		$$->width = $2;
		$$->height = $4;
		$$->style = $6;
		$$->gotstyle = TRUE;
		}
923
	| ',' expr ',' expr ',' style ',' style {
Alexandre Julliard's avatar
Alexandre Julliard committed
924 925 926 927 928 929 930 931 932 933
		$$ = new_control();
		$$->width = $2;
		$$->height = $4;
		$$->style = $6;
		$$->gotstyle = TRUE;
		$$->exstyle = $8;
		$$->gotexstyle = TRUE;
		}
	;

934
gen_ctrl: nameid_s opt_comma expr ',' ctlclass ',' style ',' expr ',' expr ',' expr ',' expr ',' style {
Alexandre Julliard's avatar
Alexandre Julliard committed
935 936 937 938 939 940 941 942 943 944 945 946 947
		$$=new_control();
		$$->title = $1;
		$$->id = $3;
		$$->ctlclass = convert_ctlclass($5);
		$$->style = $7;
		$$->gotstyle = TRUE;
		$$->x = $9;
		$$->y = $11;
		$$->width = $13;
		$$->height = $15;
		$$->exstyle = $17;
		$$->gotexstyle = TRUE;
		}
948
	| nameid_s opt_comma expr ',' ctlclass ',' style ',' expr ',' expr ',' expr ',' expr {
Alexandre Julliard's avatar
Alexandre Julliard committed
949 950 951 952 953 954 955 956 957 958 959 960 961 962
		$$=new_control();
		$$->title = $1;
		$$->id = $3;
		$$->ctlclass = convert_ctlclass($5);
		$$->style = $7;
		$$->gotstyle = TRUE;
		$$->x = $9;
		$$->y = $11;
		$$->width = $13;
		$$->height = $15;
		}
	;

opt_font
963
	: tFONT expr ',' tSTRING	{ $$ = new_font_id($2, $4, 0, 0); }
Alexandre Julliard's avatar
Alexandre Julliard committed
964 965
	;

966
/* ------------------------------ style flags ------------------------------ */
967
optional_style_pair
968 969 970
	: /* Empty */		{ $$ = NULL; }
	| ',' style		{ $$ = new_style_pair($2, 0); }
	| ',' style ',' style 	{ $$ = new_style_pair($2, $4); }
971 972
	;

973 974 975 976
style
	: style '|' style	{ $$ = new_style($1->or_mask | $3->or_mask, $1->and_mask | $3->and_mask); free($1); free($3);}
	| '(' style ')'		{ $$ = $2; }
        | any_num       	{ $$ = new_style($1, 0); }
977
        | tNOT any_num		{ $$ = new_style(0, $2); }
978
        ;
979

Alexandre Julliard's avatar
Alexandre Julliard committed
980 981 982 983 984 985 986 987 988 989 990 991 992 993
ctlclass
	: expr	{
		$$ = new_name_id();
		$$->type = name_ord;
		$$->name.i_name = $1;
		}
	| tSTRING {
		$$ = new_name_id();
		$$->type = name_str;
		$$->name.s_name = $1;
		}
	;

/* ------------------------------ DialogEx ------------------------------ */
994
dialogex: tDIALOGEX loadmemopts expr ',' expr ',' expr ',' expr helpid dlgex_attribs
Alexandre Julliard's avatar
Alexandre Julliard committed
995 996
	  tBEGIN  exctrls tEND {
		if(!win32)
997
			parser_warning("DIALOGEX not supported in 16-bit mode\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
		if($2)
		{
			$11->memopt = *($2);
			free($2);
		}
		else
			$11->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
		$11->x = $3;
		$11->y = $5;
		$11->width = $7;
		$11->height = $9;
		if($10)
		{
			$11->helpid = *($10);
			$11->gothelpid = TRUE;
			free($10);
		}
		$11->controls = get_control_head($13);
		$$ = $11;
1017 1018

		assert($$->style != NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
1019 1020
		if(!$$->gotstyle)
		{
1021
			$$->style->or_mask = WS_POPUP;
Alexandre Julliard's avatar
Alexandre Julliard committed
1022 1023 1024
			$$->gotstyle = TRUE;
		}
		if($$->title)
1025
			$$->style->or_mask |= WS_CAPTION;
Alexandre Julliard's avatar
Alexandre Julliard committed
1026
		if($$->font)
1027 1028 1029 1030 1031
			$$->style->or_mask |= DS_SETFONT;

		$$->style->or_mask &= ~($$->style->and_mask);
		$$->style->and_mask = 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
1032 1033 1034 1035 1036 1037
		if(!$$->lvc.language)
			$$->lvc.language = dup_language(currentlanguage);
		}
	;

dlgex_attribs
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
	: /* Empty */				{ $$=new_dialog(); $$->is_ex = TRUE; }
	| dlgex_attribs tSTYLE style		{ $$=dialog_style($3,$1); }
	| dlgex_attribs tEXSTYLE style		{ $$=dialog_exstyle($3,$1); }
	| dlgex_attribs tCAPTION tSTRING	{ $$=dialog_caption($3,$1); }
	| dlgex_attribs opt_font		{ $$=dialog_font($2,$1); }
	| dlgex_attribs opt_exfont		{ $$=dialog_font($2,$1); }
	| dlgex_attribs tCLASS nameid_s		{ $$=dialog_class($3,$1); }
	| dlgex_attribs tMENU nameid		{ $$=dialog_menu($3,$1); }
	| dlgex_attribs opt_language		{ $$=dialog_language($2,$1); }
	| dlgex_attribs opt_characts		{ $$=dialog_characteristics($2,$1); }
	| dlgex_attribs opt_version		{ $$=dialog_version($2,$1); }
Alexandre Julliard's avatar
Alexandre Julliard committed
1049 1050 1051
	;

exctrls	: /* Empty */				{ $$ = NULL; }
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
	| exctrls tCONTROL	gen_exctrl	{ $$=ins_ctrl(-1, 0, $3, $1); }
	| exctrls tEDITTEXT	exctrl_desc	{ $$=ins_ctrl(CT_EDIT, 0, $3, $1); }
	| exctrls tLISTBOX	exctrl_desc	{ $$=ins_ctrl(CT_LISTBOX, 0, $3, $1); }
	| exctrls tCOMBOBOX	exctrl_desc	{ $$=ins_ctrl(CT_COMBOBOX, 0, $3, $1); }
	| exctrls tSCROLLBAR	exctrl_desc	{ $$=ins_ctrl(CT_SCROLLBAR, 0, $3, $1); }
	| exctrls tCHECKBOX	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_CHECKBOX, $3, $1); }
	| exctrls tDEFPUSHBUTTON lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_DEFPUSHBUTTON, $3, $1); }
	| exctrls tGROUPBOX	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_GROUPBOX, $3, $1);}
	| exctrls tPUSHBUTTON	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_PUSHBUTTON, $3, $1); }
/*	| exctrls tPUSHBOX	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
	| exctrls tRADIOBUTTON	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_RADIOBUTTON, $3, $1); }
	| exctrls tAUTO3STATE	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTO3STATE, $3, $1); }
	| exctrls tSTATE3	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_3STATE, $3, $1); }
	| exctrls tAUTOCHECKBOX	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTOCHECKBOX, $3, $1); }
	| exctrls tAUTORADIOBUTTON lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTORADIOBUTTON, $3, $1); }
	| exctrls tLTEXT	lab_exctrl	{ $$=ins_ctrl(CT_STATIC, SS_LEFT, $3, $1); }
	| exctrls tCTEXT	lab_exctrl	{ $$=ins_ctrl(CT_STATIC, SS_CENTER, $3, $1); }
	| exctrls tRTEXT	lab_exctrl	{ $$=ins_ctrl(CT_STATIC, SS_RIGHT, $3, $1); }
Alexandre Julliard's avatar
Alexandre Julliard committed
1070
	/* special treatment for icons, as the extent is optional */
1071
	| exctrls tICON nameid_s opt_comma expr ',' expr ',' expr iconinfo {
Alexandre Julliard's avatar
Alexandre Julliard committed
1072 1073 1074 1075 1076 1077 1078 1079 1080
		$10->title = $3;
		$10->id = $5;
		$10->x = $7;
		$10->y = $9;
		$$ = ins_ctrl(CT_STATIC, SS_ICON, $10, $1);
		}
	;

gen_exctrl
1081
	: nameid_s opt_comma expr ',' ctlclass ',' style ',' expr ',' expr ',' expr ','
1082
	  expr ',' style helpid opt_data {
Alexandre Julliard's avatar
Alexandre Julliard committed
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
		$$=new_control();
		$$->title = $1;
		$$->id = $3;
		$$->ctlclass = convert_ctlclass($5);
		$$->style = $7;
		$$->gotstyle = TRUE;
		$$->x = $9;
		$$->y = $11;
		$$->width = $13;
		$$->height = $15;
		if($17)
		{
1095
			$$->exstyle = $17;
Alexandre Julliard's avatar
Alexandre Julliard committed
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
			$$->gotexstyle = TRUE;
		}
		if($18)
		{
			$$->helpid = *($18);
			$$->gothelpid = TRUE;
			free($18);
		}
		$$->extra = $19;
		}
1106
	| nameid_s opt_comma expr ',' ctlclass ',' style ',' expr ',' expr ',' expr ',' expr opt_data {
Alexandre Julliard's avatar
Alexandre Julliard committed
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
		$$=new_control();
		$$->title = $1;
		$$->id = $3;
		$$->style = $7;
		$$->gotstyle = TRUE;
		$$->ctlclass = convert_ctlclass($5);
		$$->x = $9;
		$$->y = $11;
		$$->width = $13;
		$$->height = $15;
		$$->extra = $16;
		}
	;

lab_exctrl
1122
	: nameid_s opt_comma expr ',' expr ',' expr ',' expr ',' expr optional_style_pair helpid opt_data {
Alexandre Julliard's avatar
Alexandre Julliard committed
1123
		$$=new_control();
1124
		$$->title = $1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1125 1126 1127 1128 1129 1130 1131
		$$->id = $3;
		$$->x = $5;
		$$->y = $7;
		$$->width = $9;
		$$->height = $11;
		if($12)
		{
1132
			$$->style = $12->style;
Alexandre Julliard's avatar
Alexandre Julliard committed
1133
			$$->gotstyle = TRUE;
1134 1135 1136 1137 1138 1139

			if ($12->exstyle)
			{
			    $$->exstyle = $12->exstyle;
			    $$->gotexstyle = TRUE;
			}
Alexandre Julliard's avatar
Alexandre Julliard committed
1140 1141
			free($12);
		}
1142

1143
		$$->extra = $14;
Alexandre Julliard's avatar
Alexandre Julliard committed
1144 1145 1146 1147
		}
	;

exctrl_desc
1148
	: expr ',' expr ',' expr ',' expr ',' expr optional_style_pair helpid opt_data {
Alexandre Julliard's avatar
Alexandre Julliard committed
1149 1150 1151 1152 1153 1154 1155 1156
		$$ = new_control();
		$$->id = $1;
		$$->x = $3;
		$$->y = $5;
		$$->width = $7;
		$$->height = $9;
		if($10)
		{
1157
			$$->style = $10->style;
Alexandre Julliard's avatar
Alexandre Julliard committed
1158
			$$->gotstyle = TRUE;
1159 1160 1161 1162 1163 1164

			if ($10->exstyle)
			{
			    $$->exstyle = $10->exstyle;
			    $$->gotexstyle = TRUE;
			}
Alexandre Julliard's avatar
Alexandre Julliard committed
1165 1166
			free($10);
		}
1167
		$$->extra = $12;
Alexandre Julliard's avatar
Alexandre Julliard committed
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
		}
	;

opt_data: /* Empty */	{ $$ = NULL; }
	| raw_data	{ $$ = $1; }
	;

helpid	: /* Empty */	{ $$ = NULL; }
	| ',' expr	{ $$ = new_int($2); }
	;

opt_exfont
1180
	: tFONT expr ',' tSTRING ',' expr ',' expr  opt_expr { $$ = new_font_id($2, $4, $6, $8); }
1181 1182 1183
	;

/*
1184
 * FIXME: This odd expression is here to nullify an extra token found
1185 1186 1187 1188
 * in some appstudio produced resources which appear to do nothing.
 */
opt_expr: /* Empty */	{ $$ = NULL; }
	| ',' expr	{ $$ = NULL; }
Alexandre Julliard's avatar
Alexandre Julliard committed
1189 1190 1191
	;

/* ------------------------------ Menu ------------------------------ */
1192
menu	: tMENU loadmemopts opt_lvc menu_body {
Alexandre Julliard's avatar
Alexandre Julliard committed
1193
		if(!$4)
1194
			yyerror("Menu must contain items");
Alexandre Julliard's avatar
Alexandre Julliard committed
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
		$$ = new_menu();
		if($2)
		{
			$$->memopt = *($2);
			free($2);
		}
		else
			$$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
		$$->items = get_item_head($4);
		if($3)
		{
			$$->lvc = *($3);
			free($3);
		}
		if(!$$->lvc.language)
			$$->lvc.language = dup_language(currentlanguage);
		}
	;

menu_body
	: tBEGIN item_definitions tEND	{ $$ = $2; }
	;

item_definitions
	: /* Empty */	{$$ = NULL;}
1220
	| item_definitions tMENUITEM tSTRING opt_comma expr item_options {
Alexandre Julliard's avatar
Alexandre Julliard committed
1221 1222 1223 1224 1225 1226 1227 1228
		$$=new_menu_item();
		$$->prev = $1;
		if($1)
			$1->next = $$;
		$$->id =  $5;
		$$->state = $6;
		$$->name = $3;
		}
1229
	| item_definitions tMENUITEM tSEPARATOR {
Alexandre Julliard's avatar
Alexandre Julliard committed
1230 1231 1232 1233 1234
		$$=new_menu_item();
		$$->prev = $1;
		if($1)
			$1->next = $$;
		}
1235
	| item_definitions tPOPUP tSTRING item_options menu_body {
Alexandre Julliard's avatar
Alexandre Julliard committed
1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
		$$ = new_menu_item();
		$$->prev = $1;
		if($1)
			$1->next = $$;
		$$->popup = get_item_head($5);
		$$->name = $3;
		}
	;

/* NOTE: item_options is right recursive because it would introduce
 * a shift/reduce conflict on ',' in itemex_options due to the
 * empty rule here. The parser is now forced to look beyond the ','
 * before reducing (force shift).
 * Right recursion here is not a problem because we cannot expect
 * more than 7 parserstack places to be occupied while parsing this
 * (who would want to specify a MF_x flag twice?).
 */
item_options
1254 1255 1256 1257 1258 1259 1260 1261
	:  /* Empty */			{ $$ = 0; }
	| ','		item_options	{ $$ = $2; }
	| tCHECKED	item_options	{ $$ = $2 | MF_CHECKED; }
	| tGRAYED	item_options	{ $$ = $2 | MF_GRAYED; }
	| tHELP		item_options	{ $$ = $2 | MF_HELP; }
	| tINACTIVE	item_options	{ $$ = $2 | MF_DISABLED; }
	| tMENUBARBREAK	item_options	{ $$ = $2 | MF_MENUBARBREAK; }
	| tMENUBREAK	item_options	{ $$ = $2 | MF_MENUBREAK; }
Alexandre Julliard's avatar
Alexandre Julliard committed
1262 1263 1264
	;

/* ------------------------------ MenuEx ------------------------------ */
1265
menuex	: tMENUEX loadmemopts opt_lvc menuex_body	{
Alexandre Julliard's avatar
Alexandre Julliard committed
1266
		if(!win32)
1267
			parser_warning("MENUEX not supported in 16-bit mode\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1268
		if(!$4)
1269
			yyerror("MenuEx must contain items");
1270 1271
		$$ = new_menu();
		$$->is_ex = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1272 1273 1274 1275 1276 1277 1278
		if($2)
		{
			$$->memopt = *($2);
			free($2);
		}
		else
			$$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
1279
		$$->items = get_item_head($4);
Alexandre Julliard's avatar
Alexandre Julliard committed
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295
		if($3)
		{
			$$->lvc = *($3);
			free($3);
		}
		if(!$$->lvc.language)
			$$->lvc.language = dup_language(currentlanguage);
		}
	;

menuex_body
	: tBEGIN itemex_definitions tEND { $$ = $2; }
	;

itemex_definitions
	: /* Empty */	{$$ = NULL; }
1296
	| itemex_definitions tMENUITEM tSTRING itemex_options {
1297
		$$ = new_menu_item();
Alexandre Julliard's avatar
Alexandre Julliard committed
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311
		$$->prev = $1;
		if($1)
			$1->next = $$;
		$$->name = $3;
		$$->id = $4->id;
		$$->type = $4->type;
		$$->state = $4->state;
		$$->helpid = $4->helpid;
		$$->gotid = $4->gotid;
		$$->gottype = $4->gottype;
		$$->gotstate = $4->gotstate;
		$$->gothelpid = $4->gothelpid;
		free($4);
		}
1312
	| itemex_definitions tMENUITEM tSEPARATOR {
1313
		$$ = new_menu_item();
Alexandre Julliard's avatar
Alexandre Julliard committed
1314 1315 1316 1317
		$$->prev = $1;
		if($1)
			$1->next = $$;
		}
1318
	| itemex_definitions tPOPUP tSTRING itemex_p_options menuex_body {
1319
		$$ = new_menu_item();
Alexandre Julliard's avatar
Alexandre Julliard committed
1320 1321 1322
		$$->prev = $1;
		if($1)
			$1->next = $$;
1323
		$$->popup = get_item_head($5);
Alexandre Julliard's avatar
Alexandre Julliard committed
1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
		$$->name = $3;
		$$->id = $4->id;
		$$->type = $4->type;
		$$->state = $4->state;
		$$->helpid = $4->helpid;
		$$->gotid = $4->gotid;
		$$->gottype = $4->gottype;
		$$->gotstate = $4->gotstate;
		$$->gothelpid = $4->gothelpid;
		free($4);
		}
	;

itemex_options
	: /* Empty */			{ $$ = new_itemex_opt(0, 0, 0, 0); }
	| ',' expr {
		$$ = new_itemex_opt($2, 0, 0, 0);
		$$->gotid = TRUE;
		}
	| ',' e_expr ',' e_expr item_options {
		$$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $5, 0);
		$$->gotid = TRUE;
		$$->gottype = TRUE;
		$$->gotstate = TRUE;
1348 1349
		free($2);
		free($4);
Alexandre Julliard's avatar
Alexandre Julliard committed
1350 1351 1352 1353 1354 1355
		}
	| ',' e_expr ',' e_expr ',' expr {
		$$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $6, 0);
		$$->gotid = TRUE;
		$$->gottype = TRUE;
		$$->gotstate = TRUE;
1356 1357
		free($2);
		free($4);
Alexandre Julliard's avatar
Alexandre Julliard committed
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368
		}
	;

itemex_p_options
	: /* Empty */			{ $$ = new_itemex_opt(0, 0, 0, 0); }
	| ',' expr {
		$$ = new_itemex_opt($2, 0, 0, 0);
		$$->gotid = TRUE;
		}
	| ',' e_expr ',' expr {
		$$ = new_itemex_opt($2 ? *($2) : 0, $4, 0, 0);
1369
		free($2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1370 1371 1372 1373 1374
		$$->gotid = TRUE;
		$$->gottype = TRUE;
		}
	| ',' e_expr ',' e_expr ',' expr {
		$$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $6, 0);
1375 1376
		free($2);
		free($4);
Alexandre Julliard's avatar
Alexandre Julliard committed
1377 1378 1379 1380 1381 1382
		$$->gotid = TRUE;
		$$->gottype = TRUE;
		$$->gotstate = TRUE;
		}
	| ',' e_expr ',' e_expr ',' e_expr ',' expr {
		$$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $6 ? *($6) : 0, $8);
1383 1384 1385
		free($2);
		free($4);
		free($6);
Alexandre Julliard's avatar
Alexandre Julliard committed
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403
		$$->gotid = TRUE;
		$$->gottype = TRUE;
		$$->gotstate = TRUE;
		$$->gothelpid = TRUE;
		}
	;

/* ------------------------------ StringTable ------------------------------ */
/* Stringtables are parsed differently than other resources because their
 * layout is substantially different from other resources.
 * The table is parsed through a _global_ variable 'tagstt' which holds the
 * current stringtable descriptor (stringtable_t *) and 'sttres' that holds a
 * list of stringtables of different languages.
 */
stringtable
	: stt_head tBEGIN strings tEND {
		if(!$3)
		{
1404
			yyerror("Stringtable must have at least one entry");
Alexandre Julliard's avatar
Alexandre Julliard committed
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430
		}
		else
		{
			stringtable_t *stt;
			/* Check if we added to a language table or created
			 * a new one.
			 */
			 for(stt = sttres; stt; stt = stt->next)
			 {
				if(stt == tagstt)
					break;
			 }
			 if(!stt)
			 {
				/* It is a new one */
				if(sttres)
				{
					sttres->prev = tagstt;
					tagstt->next = sttres;
					sttres = tagstt;
				}
				else
					sttres = tagstt;
			 }
			 /* Else were done */
		}
1431 1432
		free(tagstt_memopt);
		tagstt_memopt = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1433 1434 1435 1436 1437 1438

		$$ = tagstt;
		}
	;

/* This is to get the language of the currently parsed stringtable */
1439
stt_head: tSTRINGTABLE loadmemopts opt_lvc {
Alexandre Julliard's avatar
Alexandre Julliard committed
1440 1441 1442 1443 1444
		if((tagstt = find_stringtable($3)) == NULL)
			tagstt = new_stringtable($3);
		tagstt_memopt = $2;
		tagstt_version = $3->version;
		tagstt_characts = $3->characts;
1445
		free($3);
Alexandre Julliard's avatar
Alexandre Julliard committed
1446 1447 1448 1449 1450 1451 1452
		}
	;

strings	: /* Empty */	{ $$ = NULL; }
	| strings expr opt_comma tSTRING {
		int i;
		assert(tagstt != NULL);
1453
		if($2 > 65535 || $2 < -32768)
1454
			yyerror("Stringtable entry's ID out of range (%d)", $2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1455 1456 1457 1458
		/* Search for the ID */
		for(i = 0; i < tagstt->nentries; i++)
		{
			if(tagstt->entries[i].id == $2)
1459
				yyerror("Stringtable ID %d already in use", $2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472
		}
		/* If we get here, then we have a new unique entry */
		tagstt->nentries++;
		tagstt->entries = xrealloc(tagstt->entries, sizeof(tagstt->entries[0]) * tagstt->nentries);
		tagstt->entries[tagstt->nentries-1].id = $2;
		tagstt->entries[tagstt->nentries-1].str = $4;
		if(tagstt_memopt)
			tagstt->entries[tagstt->nentries-1].memopt = *tagstt_memopt;
		else
			tagstt->entries[tagstt->nentries-1].memopt = WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE;
		tagstt->entries[tagstt->nentries-1].version = tagstt_version;
		tagstt->entries[tagstt->nentries-1].characts = tagstt_characts;

1473
		if(pedantic && !$4->size)
1474
			parser_warning("Zero length strings make no sense\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1475
		if(!win32 && $4->size > 254)
1476
			yyerror("Stringtable entry more than 254 characters");
Alexandre Julliard's avatar
Alexandre Julliard committed
1477
		if(win32 && $4->size > 65534) /* Hmm..., does this happen? */
1478
			yyerror("Stringtable entry more than 65534 characters (probably something else that went wrong)");
Alexandre Julliard's avatar
Alexandre Julliard committed
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489
		$$ = tagstt;
		}
	;

opt_comma	/* There seem to be two ways to specify a stringtable... */
	: /* Empty */
	| ','
	;

/* ------------------------------ VersionInfo ------------------------------ */
versioninfo
1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501
	: tVERSIONINFO loadmemopts fix_version tBEGIN ver_blocks tEND {
		$$ = $3;
		if($2)
		{
			$$->memopt = *($2);
			free($2);
		}
		else
			$$->memopt = WRC_MO_MOVEABLE | (win32 ? WRC_MO_PURE : 0);
		$$->blocks = get_ver_block_head($5);
		/* Set language; there is no version or characteristics */
		$$->lvc.language = dup_language(currentlanguage);
Alexandre Julliard's avatar
Alexandre Julliard committed
1502 1503 1504 1505 1506
		}
	;

fix_version
	: /* Empty */			{ $$ = new_versioninfo(); }
1507
	| fix_version tFILEVERSION expr ',' expr ',' expr ',' expr {
Alexandre Julliard's avatar
Alexandre Julliard committed
1508
		if($1->gotit.fv)
1509
			yyerror("FILEVERSION already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1510 1511 1512 1513 1514 1515 1516
		$$ = $1;
		$$->filever_maj1 = $3;
		$$->filever_maj2 = $5;
		$$->filever_min1 = $7;
		$$->filever_min2 = $9;
		$$->gotit.fv = 1;
		}
1517
	| fix_version tPRODUCTVERSION expr ',' expr ',' expr ',' expr {
Alexandre Julliard's avatar
Alexandre Julliard committed
1518
		if($1->gotit.pv)
1519
			yyerror("PRODUCTVERSION already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1520 1521 1522 1523 1524 1525 1526
		$$ = $1;
		$$->prodver_maj1 = $3;
		$$->prodver_maj2 = $5;
		$$->prodver_min1 = $7;
		$$->prodver_min2 = $9;
		$$->gotit.pv = 1;
		}
1527
	| fix_version tFILEFLAGS expr {
Alexandre Julliard's avatar
Alexandre Julliard committed
1528
		if($1->gotit.ff)
1529
			yyerror("FILEFLAGS already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1530 1531 1532 1533
		$$ = $1;
		$$->fileflags = $3;
		$$->gotit.ff = 1;
		}
1534
	| fix_version tFILEFLAGSMASK expr {
Alexandre Julliard's avatar
Alexandre Julliard committed
1535
		if($1->gotit.ffm)
1536
			yyerror("FILEFLAGSMASK already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1537 1538 1539 1540
		$$ = $1;
		$$->fileflagsmask = $3;
		$$->gotit.ffm = 1;
		}
1541
	| fix_version tFILEOS expr {
Alexandre Julliard's avatar
Alexandre Julliard committed
1542
		if($1->gotit.fo)
1543
			yyerror("FILEOS already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1544 1545 1546 1547
		$$ = $1;
		$$->fileos = $3;
		$$->gotit.fo = 1;
		}
1548
	| fix_version tFILETYPE expr {
Alexandre Julliard's avatar
Alexandre Julliard committed
1549
		if($1->gotit.ft)
1550
			yyerror("FILETYPE already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1551 1552 1553 1554
		$$ = $1;
		$$->filetype = $3;
		$$->gotit.ft = 1;
		}
1555
	| fix_version tFILESUBTYPE expr {
Alexandre Julliard's avatar
Alexandre Julliard committed
1556
		if($1->gotit.fst)
1557
			yyerror("FILESUBTYPE already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
		$$ = $1;
		$$->filesubtype = $3;
		$$->gotit.fst = 1;
		}
	;

ver_blocks
	: /* Empty */			{ $$ = NULL; }
	| ver_blocks ver_block {
		$$ = $2;
		$$->prev = $1;
		if($1)
			$1->next = $$;
		}
	;

ver_block
1575
	: tBLOCK tSTRING tBEGIN ver_values tEND {
Alexandre Julliard's avatar
Alexandre Julliard committed
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597
		$$ = new_ver_block();
		$$->name = $2;
		$$->values = get_ver_value_head($4);
		}
	;

ver_values
	: /* Empty */			{ $$ = NULL; }
	| ver_values ver_value {
		$$ = $2;
		$$->prev = $1;
		if($1)
			$1->next = $$;
		}
	;

ver_value
	: ver_block {
		$$ = new_ver_value();
		$$->type = val_block;
		$$->value.block = $1;
		}
1598
	| tVALUE tSTRING ',' tSTRING {
Alexandre Julliard's avatar
Alexandre Julliard committed
1599 1600 1601 1602 1603
		$$ = new_ver_value();
		$$->type = val_str;
		$$->key = $2;
		$$->value.str = $4;
		}
1604
	| tVALUE tSTRING ',' ver_words {
Alexandre Julliard's avatar
Alexandre Julliard committed
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
		$$ = new_ver_value();
		$$->type = val_words;
		$$->key = $2;
		$$->value.words = $4;
		}
	;

ver_words
	: expr			{ $$ = new_ver_words($1); }
	| ver_words ',' expr	{ $$ = add_ver_words($1, $3); }
	;

1617
/* ------------------------------ Toolbar ------------------------------ */
1618
toolbar: tTOOLBAR loadmemopts expr ',' expr opt_lvc tBEGIN toolbar_items tEND {
1619 1620 1621 1622 1623 1624
		int nitems;
		toolbar_item_t *items = get_tlbr_buttons_head($8, &nitems);
		$$ = new_toolbar($3, $5, items, nitems);
		if($2)
		{
			$$->memopt = *($2);
1625
			free($2);
1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
		}
		else
		{
			$$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
		}
		if($6)
		{
			$$->lvc = *($6);
			free($6);
		}
		if(!$$->lvc.language)
		{
			$$->lvc.language = dup_language(currentlanguage);
		}
		}
	;

toolbar_items
	:  /* Empty */			{ $$ = NULL; }
1645
	| toolbar_items tBUTTON expr	{
1646 1647
		toolbar_item_t *idrec = new_toolbar_item();
		idrec->id = $3;
1648
		$$ = ins_tlbr_button($1, idrec);
1649
		}
1650
	| toolbar_items tSEPARATOR	{
1651 1652
		toolbar_item_t *idrec = new_toolbar_item();
		idrec->id = 0;
1653
		$$ = ins_tlbr_button($1, idrec);
1654 1655 1656
	}
	;

Alexandre Julliard's avatar
Alexandre Julliard committed
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
/* ------------------------------ Memory options ------------------------------ */
loadmemopts
	: /* Empty */		{ $$ = NULL; }
	| loadmemopts lamo {
		if($1)
		{
			*($1) |= *($2);
			$$ = $1;
			free($2);
		}
		else
			$$ = $2;
		}
	| loadmemopts lama {
		if($1)
		{
			*($1) &= *($2);
			$$ = $1;
			free($2);
		}
		else
		{
			*$2 &= WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE | WRC_MO_PURE;
			$$ = $2;
		}
		}
	;

1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700
lamo	: tPRELOAD	{ $$ = new_int(WRC_MO_PRELOAD);
			  if (win32 && pedantic) parser_warning("PRELOAD is ignored in 32-bit mode\n"); }
	| tMOVEABLE	{ $$ = new_int(WRC_MO_MOVEABLE);
			  if (win32 && pedantic) parser_warning("MOVEABLE is ignored in 32-bit mode\n"); }
	| tDISCARDABLE	{ $$ = new_int(WRC_MO_DISCARDABLE);
			  if (win32 && pedantic) parser_warning("DISCARDABLE is ignored in 32-bit mode\n"); }
	| tPURE		{ $$ = new_int(WRC_MO_PURE);
			  if (win32 && pedantic) parser_warning("PURE is ignored in 32-bit mode\n"); }
	;

lama	: tLOADONCALL	{ $$ = new_int(~WRC_MO_PRELOAD);
			  if (win32 && pedantic) parser_warning("LOADONCALL is ignored in 32-bit mode\n"); }
	| tFIXED	{ $$ = new_int(~WRC_MO_MOVEABLE);
			  if (win32 && pedantic) parser_warning("FIXED is ignored in 32-bit mode\n"); }
	| tIMPURE	{ $$ = new_int(~WRC_MO_PURE);
			  if (win32 && pedantic) parser_warning("IMPURE is ignored in 32-bit mode\n"); }
Alexandre Julliard's avatar
Alexandre Julliard committed
1701 1702 1703 1704 1705 1706
	;

/* ------------------------------ Win32 options ------------------------------ */
opt_lvc	: /* Empty */		{ $$ = new_lvc(); }
	| opt_lvc opt_language {
		if(!win32)
1707
			parser_warning("LANGUAGE not supported in 16-bit mode\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1708
		if($1->language)
1709
			yyerror("Language already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1710 1711 1712 1713 1714
		$$ = $1;
		$1->language = $2;
		}
	| opt_lvc opt_characts {
		if(!win32)
1715
			parser_warning("CHARACTERISTICS not supported in 16-bit mode\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1716
		if($1->characts)
1717
			yyerror("Characteristics already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1718 1719 1720 1721 1722
		$$ = $1;
		$1->characts = $2;
		}
	| opt_lvc opt_version {
		if(!win32)
1723
			parser_warning("VERSION not supported in 16-bit mode\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1724
		if($1->version)
1725
			yyerror("Version already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1726 1727 1728 1729 1730
		$$ = $1;
		$1->version = $2;
		}
	;

1731 1732 1733 1734 1735 1736 1737
	/*
	 * This here is another s/r conflict on {bi,u}nary + and -.
	 * It is due to the look-ahead which must determine when the
	 * rule opt_language ends. It could be solved with adding a
	 * tNL at the end, but that seems unreasonable to do.
	 * The conflict is now moved to the expression handling below.
	 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1738
opt_language
1739 1740
	: tLANGUAGE expr ',' expr	{ $$ = new_language($2, $4);
					  if (get_language_codepage($2, $4) == -1)
1741
						yyerror( "Language %04x is not supported", ($4<<10) + $2);
1742
					}
Alexandre Julliard's avatar
Alexandre Julliard committed
1743 1744 1745
	;

opt_characts
1746
	: tCHARACTERISTICS expr		{ $$ = new_characts($2); }
Alexandre Julliard's avatar
Alexandre Julliard committed
1747 1748 1749
	;

opt_version
1750
	: tVERSION expr			{ $$ = new_version($2); }
Alexandre Julliard's avatar
Alexandre Julliard committed
1751 1752
	;

1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765
/* ------------------------------ Raw data handling ------------------------------ */
raw_data: opt_lvc tBEGIN raw_elements tEND {
		if($1)
		{
			$3->lvc = *($1);
			free($1);
		}

		if(!$3->lvc.language)
			$3->lvc.language = dup_language(currentlanguage);

		$$ = $3;
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
1766 1767 1768
	;

raw_elements
1769 1770
	: tRAWDATA			{ $$ = $1; }
	| tNUMBER			{ $$ = int2raw_data($1); }
1771
	| '-' tNUMBER	           	{ $$ = int2raw_data(-($2)); }
1772
	| tLNUMBER			{ $$ = long2raw_data($1); }
1773
	| '-' tLNUMBER	           	{ $$ = long2raw_data(-($2)); }
Alexandre Julliard's avatar
Alexandre Julliard committed
1774
	| tSTRING			{ $$ = str2raw_data($1); }
1775 1776
	| raw_elements opt_comma tRAWDATA { $$ = merge_raw_data($1, $3); free($3->data); free($3); }
	| raw_elements opt_comma tNUMBER  { $$ = merge_raw_data_int($1, $3); }
1777
	| raw_elements opt_comma '-' tNUMBER  { $$ = merge_raw_data_int($1, -($4)); }
1778
	| raw_elements opt_comma tLNUMBER { $$ = merge_raw_data_long($1, $3); }
1779
	| raw_elements opt_comma '-' tLNUMBER { $$ = merge_raw_data_long($1, -($4)); }
1780
	| raw_elements opt_comma tSTRING  { $$ = merge_raw_data_str($1, $3); }
Alexandre Julliard's avatar
Alexandre Julliard committed
1781 1782
	;

1783
/* File data or raw data */
1784
file_raw: filename	{ $$ = load_file($1,dup_language(currentlanguage)); }
1785 1786 1787
	| raw_data	{ $$ = $1; }
	;

Alexandre Julliard's avatar
Alexandre Julliard committed
1788
/* ------------------------------ Win32 expressions ------------------------------ */
1789 1790
/* All win16 numbers are also handled here. This is inconsistent with MS
 * resource compiler, but what the heck, it's just handy to have.
Alexandre Julliard's avatar
Alexandre Julliard committed
1791 1792 1793 1794
 */
e_expr	: /* Empty */	{ $$ = 0; }
	| expr		{ $$ = new_int($1); }
	;
1795 1796

/* This rule moves ALL s/r conflicts on {bi,u}nary - and + to here */
Eric Pouech's avatar
Eric Pouech committed
1797
expr	: xpr	{ $$ = ($1); }
Alexandre Julliard's avatar
Alexandre Julliard committed
1798 1799 1800 1801 1802 1803 1804 1805
	;

xpr	: xpr '+' xpr	{ $$ = ($1) + ($3); }
	| xpr '-' xpr	{ $$ = ($1) - ($3); }
	| xpr '|' xpr	{ $$ = ($1) | ($3); }
	| xpr '&' xpr	{ $$ = ($1) & ($3); }
	| xpr '*' xpr	{ $$ = ($1) * ($3); }
	| xpr '/' xpr	{ $$ = ($1) / ($3); }
1806
	| xpr '^' xpr	{ $$ = ($1) ^ ($3); }
Alexandre Julliard's avatar
Alexandre Julliard committed
1807
	| '~' xpr	{ $$ = ~($2); }
1808 1809
	| '-' xpr %prec pUPM	{ $$ = -($2); }
	| '+' xpr %prec pUPM	{ $$ = $2; }
Alexandre Julliard's avatar
Alexandre Julliard committed
1810
	| '(' xpr ')'	{ $$ = $2; }
1811 1812
	| any_num	{ $$ = $1; }
	| tNOT any_num	{ $$ = ~($2); }
Alexandre Julliard's avatar
Alexandre Julliard committed
1813
	;
1814

1815 1816
any_num	: tNUMBER	{ $$ = $1; }
	| tLNUMBER	{ $$ = $1; }
1817 1818
	;

Alexandre Julliard's avatar
Alexandre Julliard committed
1819 1820
%%
/* Dialog specific functions */
1821
static dialog_t *dialog_style(style_t * st, dialog_t *dlg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1822 1823
{
	assert(dlg != NULL);
1824 1825 1826 1827 1828
	if(dlg->style == NULL)
	{
		dlg->style = new_style(0,0);
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
1829 1830
	if(dlg->gotstyle)
	{
1831
		parser_warning("Style already defined, or-ing together\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1832
	}
1833 1834 1835 1836 1837 1838 1839
	else
	{
		dlg->style->or_mask = 0;
		dlg->style->and_mask = 0;
	}
	dlg->style->or_mask |= st->or_mask;
	dlg->style->and_mask |= st->and_mask;
Alexandre Julliard's avatar
Alexandre Julliard committed
1840
	dlg->gotstyle = TRUE;
1841
	free(st);
Alexandre Julliard's avatar
Alexandre Julliard committed
1842 1843 1844
	return dlg;
}

1845
static dialog_t *dialog_exstyle(style_t *st, dialog_t *dlg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1846 1847
{
	assert(dlg != NULL);
1848 1849 1850 1851 1852
	if(dlg->exstyle == NULL)
	{
		dlg->exstyle = new_style(0,0);
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
1853 1854
	if(dlg->gotexstyle)
	{
1855
		parser_warning("ExStyle already defined, or-ing together\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1856
	}
1857 1858 1859 1860 1861 1862 1863
	else
	{
		dlg->exstyle->or_mask = 0;
		dlg->exstyle->and_mask = 0;
	}
	dlg->exstyle->or_mask |= st->or_mask;
	dlg->exstyle->and_mask |= st->and_mask;
Alexandre Julliard's avatar
Alexandre Julliard committed
1864
	dlg->gotexstyle = TRUE;
1865
	free(st);
Alexandre Julliard's avatar
Alexandre Julliard committed
1866 1867 1868
	return dlg;
}

1869
static dialog_t *dialog_caption(string_t *s, dialog_t *dlg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1870 1871 1872
{
	assert(dlg != NULL);
	if(dlg->title)
1873
		yyerror("Caption already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1874 1875 1876 1877
	dlg->title = s;
	return dlg;
}

1878
static dialog_t *dialog_font(font_id_t *f, dialog_t *dlg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1879 1880 1881
{
	assert(dlg != NULL);
	if(dlg->font)
1882
		yyerror("Font already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1883 1884 1885 1886
	dlg->font = f;
	return dlg;
}

1887
static dialog_t *dialog_class(name_id_t *n, dialog_t *dlg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1888 1889 1890
{
	assert(dlg != NULL);
	if(dlg->dlgclass)
1891
		yyerror("Class already defined");
Alexandre Julliard's avatar
Alexandre Julliard committed
1892 1893 1894 1895
	dlg->dlgclass = n;
	return dlg;
}

1896
static dialog_t *dialog_menu(name_id_t *m, dialog_t *dlg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1897 1898 1899 1900 1901 1902 1903 1904
{
	assert(dlg != NULL);
	if(dlg->menu)
		yyerror("Menu already defined");
	dlg->menu = m;
	return dlg;
}

1905
static dialog_t *dialog_language(language_t *l, dialog_t *dlg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1906 1907 1908 1909 1910 1911 1912 1913
{
	assert(dlg != NULL);
	if(dlg->lvc.language)
		yyerror("Language already defined");
	dlg->lvc.language = l;
	return dlg;
}

1914
static dialog_t *dialog_characteristics(characts_t *c, dialog_t *dlg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1915 1916 1917 1918 1919 1920 1921 1922
{
	assert(dlg != NULL);
	if(dlg->lvc.characts)
		yyerror("Characteristics already defined");
	dlg->lvc.characts = c;
	return dlg;
}

1923
static dialog_t *dialog_version(version_t *v, dialog_t *dlg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1924 1925 1926 1927 1928 1929 1930 1931 1932
{
	assert(dlg != NULL);
	if(dlg->lvc.version)
		yyerror("Version already defined");
	dlg->lvc.version = v;
	return dlg;
}

/* Controls specific functions */
1933
static control_t *ins_ctrl(int type, int special_style, control_t *ctrl, control_t *prev)
Alexandre Julliard's avatar
Alexandre Julliard committed
1934
{
1935 1936 1937
	/* Hm... this seems to be jammed in at all time... */
	int defaultstyle = WS_CHILD | WS_VISIBLE;

Alexandre Julliard's avatar
Alexandre Julliard committed
1938 1939
	assert(ctrl != NULL);
	ctrl->prev = prev;
1940

Alexandre Julliard's avatar
Alexandre Julliard committed
1941 1942
	if(prev)
		prev->next = ctrl;
1943

1944 1945 1946 1947 1948 1949 1950 1951
	/* Check for duplicate identifiers */
	while (prev)
	{
		if (ctrl->id != -1 && ctrl->id == prev->id)
                        parser_warning("Duplicate dialog control id %d\n", ctrl->id);
		prev = prev->prev;
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
1952 1953 1954 1955 1956 1957 1958 1959 1960 1961
	if(type != -1)
	{
		ctrl->ctlclass = new_name_id();
		ctrl->ctlclass->type = name_ord;
		ctrl->ctlclass->name.i_name = type;
	}

	switch(type)
	{
	case CT_BUTTON:
1962 1963
		if(special_style != BS_GROUPBOX && special_style != BS_RADIOBUTTON)
			defaultstyle |= WS_TABSTOP;
Alexandre Julliard's avatar
Alexandre Julliard committed
1964 1965
		break;
	case CT_EDIT:
1966
		defaultstyle |= WS_TABSTOP | WS_BORDER;
Alexandre Julliard's avatar
Alexandre Julliard committed
1967 1968
		break;
	case CT_LISTBOX:
1969
		defaultstyle |= LBS_NOTIFY | WS_BORDER;
Alexandre Julliard's avatar
Alexandre Julliard committed
1970 1971
		break;
	case CT_COMBOBOX:
1972 1973
                if (!(ctrl->style->or_mask & (CBS_SIMPLE | CBS_DROPDOWN | CBS_DROPDOWNLIST)))
                    defaultstyle |= CBS_SIMPLE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1974 1975
		break;
	case CT_STATIC:
1976 1977
		if(special_style == SS_CENTER || special_style == SS_LEFT || special_style == SS_RIGHT)
			defaultstyle |= WS_GROUP;
Alexandre Julliard's avatar
Alexandre Julliard committed
1978 1979 1980 1981 1982 1983 1984 1985
		break;
	}

	if(!ctrl->gotstyle)	/* Handle default style setting */
	{
		switch(type)
		{
		case CT_EDIT:
1986
			defaultstyle |= ES_LEFT;
Alexandre Julliard's avatar
Alexandre Julliard committed
1987 1988
			break;
		case CT_LISTBOX:
1989
			defaultstyle |= LBS_NOTIFY;
Alexandre Julliard's avatar
Alexandre Julliard committed
1990 1991
			break;
		case CT_COMBOBOX:
1992
			defaultstyle |= CBS_SIMPLE | WS_TABSTOP;
Alexandre Julliard's avatar
Alexandre Julliard committed
1993 1994
			break;
		case CT_SCROLLBAR:
1995
			defaultstyle |= SBS_HORZ;
Alexandre Julliard's avatar
Alexandre Julliard committed
1996 1997
			break;
		case CT_BUTTON:
1998
			switch(special_style)
Alexandre Julliard's avatar
Alexandre Julliard committed
1999 2000 2001 2002 2003 2004 2005 2006 2007
			{
			case BS_CHECKBOX:
			case BS_DEFPUSHBUTTON:
			case BS_PUSHBUTTON:
/*			case BS_PUSHBOX:	*/
			case BS_AUTORADIOBUTTON:
			case BS_AUTO3STATE:
			case BS_3STATE:
			case BS_AUTOCHECKBOX:
2008
				defaultstyle |= WS_TABSTOP;
Alexandre Julliard's avatar
Alexandre Julliard committed
2009 2010
				break;
			default:
2011
				parser_warning("Unknown default button control-style 0x%08x\n", special_style);
2012
			case BS_GROUPBOX:
Alexandre Julliard's avatar
Alexandre Julliard committed
2013 2014 2015 2016 2017 2018
			case BS_RADIOBUTTON:
				break;
			}
			break;

		case CT_STATIC:
2019
			switch(special_style)
Alexandre Julliard's avatar
Alexandre Julliard committed
2020 2021 2022 2023
			{
			case SS_LEFT:
			case SS_RIGHT:
			case SS_CENTER:
2024
				defaultstyle |= WS_GROUP;
Alexandre Julliard's avatar
Alexandre Julliard committed
2025 2026 2027 2028
				break;
			case SS_ICON:	/* Special case */
				break;
			default:
2029
				parser_warning("Unknown default static control-style 0x%08x\n", special_style);
Alexandre Julliard's avatar
Alexandre Julliard committed
2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
				break;
			}
			break;
		case -1:	/* Generic control */
			goto byebye;

		default:
			yyerror("Internal error (report this): Got weird control type 0x%08x", type);
		}
	}

	/* The SS_ICON flag is always forced in for icon controls */
2042 2043
	if(type == CT_STATIC && special_style == SS_ICON)
		defaultstyle |= SS_ICON;
Alexandre Julliard's avatar
Alexandre Julliard committed
2044

2045 2046 2047 2048 2049
	if (!ctrl->gotstyle)
		ctrl->style = new_style(0,0);

	/* combine all styles */
	ctrl->style->or_mask = ctrl->style->or_mask | defaultstyle | special_style;
Alexandre Julliard's avatar
Alexandre Julliard committed
2050 2051
	ctrl->gotstyle = TRUE;
byebye:
2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062
	/* combine with NOT mask */
	if (ctrl->gotstyle)
	{
		ctrl->style->or_mask &= ~(ctrl->style->and_mask);
		ctrl->style->and_mask = 0;
	}
	if (ctrl->gotexstyle)
	{
		ctrl->exstyle->or_mask &= ~(ctrl->exstyle->and_mask);
		ctrl->exstyle->and_mask = 0;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
2063 2064 2065
	return ctrl;
}

2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109
static int get_class_idW(const WCHAR *cc)
{
        static const WCHAR szBUTTON[]    = {'B','U','T','T','O','N',0};
        static const WCHAR szCOMBOBOX[]  = {'C','O','M','B','O','B','O','X',0};
        static const WCHAR szLISTBOX[]   = {'L','I','S','T','B','O','X',0};
        static const WCHAR szEDIT[]      = {'E','D','I','T',0};
        static const WCHAR szSTATIC[]    = {'S','T','A','T','I','C',0};
        static const WCHAR szSCROLLBAR[] = {'S','C','R','O','L','L','B','A','R',0};

        if(!strcmpiW(szBUTTON, cc))
                return CT_BUTTON;
        if(!strcmpiW(szCOMBOBOX, cc))
                return CT_COMBOBOX;
        if(!strcmpiW(szLISTBOX, cc))
                return CT_LISTBOX;
        if(!strcmpiW(szEDIT, cc))
                return CT_EDIT;
        if(!strcmpiW(szSTATIC, cc))
                return CT_STATIC;
        if(!strcmpiW(szSCROLLBAR, cc))
                return CT_SCROLLBAR;

        return -1;
}

static int get_class_idA(const char *cc)
{
        if(!strcasecmp("BUTTON", cc))
                return CT_BUTTON;
        if(!strcasecmp("COMBOBOX", cc))
                return CT_COMBOBOX;
        if(!strcasecmp("LISTBOX", cc))
                return CT_LISTBOX;
        if(!strcasecmp("EDIT", cc))
                return CT_EDIT;
        if(!strcasecmp("STATIC", cc))
                return CT_STATIC;
        if(!strcasecmp("SCROLLBAR", cc))
                return CT_SCROLLBAR;

        return -1;
}


2110
static name_id_t *convert_ctlclass(name_id_t *cls)
Alexandre Julliard's avatar
Alexandre Julliard committed
2111 2112 2113 2114 2115 2116
{
	int iclass;

	if(cls->type == name_ord)
		return cls;
	assert(cls->type == name_str);
2117 2118 2119 2120 2121 2122
        if(cls->name.s_name->type == str_unicode)
                iclass = get_class_idW(cls->name.s_name->str.wstr);
        else
                iclass = get_class_idA(cls->name.s_name->str.cstr);

        if (iclass == -1)
Alexandre Julliard's avatar
Alexandre Julliard committed
2123 2124 2125 2126 2127 2128 2129 2130 2131 2132
		return cls;	/* No default, return user controlclass */

	free(cls->name.s_name->str.cstr);
	free(cls->name.s_name);
	cls->type = name_ord;
	cls->name.i_name = iclass;
	return cls;
}

/* Accelerator specific functions */
2133
static event_t *add_event(int key, int id, int flags, event_t *prev)
Alexandre Julliard's avatar
Alexandre Julliard committed
2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148
{
	event_t *ev = new_event();

	if((flags & (WRC_AF_VIRTKEY | WRC_AF_ASCII)) == (WRC_AF_VIRTKEY | WRC_AF_ASCII))
		yyerror("Cannot use both ASCII and VIRTKEY");

	ev->key = key;
	ev->id = id;
	ev->flags = flags & ~WRC_AF_ASCII;
	ev->prev = prev;
	if(prev)
		prev->next = ev;
	return ev;
}

2149
static event_t *add_string_event(string_t *key, int id, int flags, event_t *prev)
Alexandre Julliard's avatar
Alexandre Julliard committed
2150
{
2151
    event_t *ev = new_event();
Alexandre Julliard's avatar
Alexandre Julliard committed
2152

2153
    ev->str = key;
2154 2155 2156 2157 2158 2159
    ev->id = id;
    ev->flags = flags & ~WRC_AF_ASCII;
    ev->prev = prev;
    if(prev)
        prev->next = ev;
    return ev;
Alexandre Julliard's avatar
Alexandre Julliard committed
2160 2161 2162
}

/* MenuEx specific functions */
2163
static itemex_opt_t *new_itemex_opt(int id, int type, int state, int helpid)
Alexandre Julliard's avatar
Alexandre Julliard committed
2164
{
2165
	itemex_opt_t *opt = xmalloc(sizeof(itemex_opt_t));
2166
	memset( opt, 0, sizeof(*opt) );
Alexandre Julliard's avatar
Alexandre Julliard committed
2167 2168 2169 2170 2171 2172 2173 2174
	opt->id = id;
	opt->type = type;
	opt->state = state;
	opt->helpid = helpid;
	return opt;
}

/* Raw data functions */
2175
static raw_data_t *load_file(string_t *filename, language_t *lang)
Alexandre Julliard's avatar
Alexandre Julliard committed
2176
{
2177 2178
	FILE *fp = NULL;
	char *path;
Alexandre Julliard's avatar
Alexandre Julliard committed
2179
	raw_data_t *rd;
2180 2181
	string_t *name;
	int codepage = get_language_codepage(lang->id, lang->sub);
2182

2183 2184 2185 2186
	/* FIXME: we may want to use utf-8 here */
	if (codepage <= 0 && filename->type != str_char)
		yyerror("Cannot convert filename to ASCII string");
	name = convert_string( filename, str_char, codepage );
2187
	if (!(path = wpp_find_include(name->str.cstr, input_name)))
Alexandre Julliard's avatar
Alexandre Julliard committed
2188
		yyerror("Cannot open file %s", name->str.cstr);
2189 2190 2191
	if (!(fp = fopen( path, "rb" )))
		yyerror("Cannot open file %s", name->str.cstr);
	free( path );
Alexandre Julliard's avatar
Alexandre Julliard committed
2192 2193 2194 2195
	rd = new_raw_data();
	fseek(fp, 0, SEEK_END);
	rd->size = ftell(fp);
	fseek(fp, 0, SEEK_SET);
2196 2197
	if (rd->size)
	{
2198
		rd->data = xmalloc(rd->size);
2199 2200 2201
		fread(rd->data, rd->size, 1, fp);
	}
	else rd->data = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
2202
	fclose(fp);
2203 2204
	rd->lvc.language = lang;
	free_string(name);
Alexandre Julliard's avatar
Alexandre Julliard committed
2205 2206 2207
	return rd;
}

2208
static raw_data_t *int2raw_data(int i)
Alexandre Julliard's avatar
Alexandre Julliard committed
2209 2210
{
	raw_data_t *rd;
2211

2212 2213
	if( ( i >= 0 && (int)((unsigned short)i) != i) ||
            ( i < 0  && (int)((short)i) != i) )
2214
		parser_warning("Integer constant out of 16bit range (%d), truncated to %d\n", i, (short)i);
2215

Alexandre Julliard's avatar
Alexandre Julliard committed
2216 2217
	rd = new_raw_data();
	rd->size = sizeof(short);
2218
	rd->data = xmalloc(rd->size);
2219 2220
	switch(byteorder)
	{
2221 2222
#ifdef WORDS_BIGENDIAN
	default:
2223
#endif
2224 2225 2226
	case WRC_BO_BIG:
		rd->data[0] = HIBYTE(i);
		rd->data[1] = LOBYTE(i);
2227
		break;
2228 2229

#ifndef WORDS_BIGENDIAN
2230
	default:
2231 2232 2233 2234
#endif
	case WRC_BO_LITTLE:
		rd->data[1] = HIBYTE(i);
		rd->data[0] = LOBYTE(i);
2235 2236
		break;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
2237 2238 2239
	return rd;
}

2240
static raw_data_t *long2raw_data(int i)
2241 2242 2243 2244
{
	raw_data_t *rd;
	rd = new_raw_data();
	rd->size = sizeof(int);
2245
	rd->data = xmalloc(rd->size);
2246 2247
	switch(byteorder)
	{
2248 2249
#ifdef WORDS_BIGENDIAN
	default:
2250
#endif
2251 2252 2253 2254 2255
	case WRC_BO_BIG:
		rd->data[0] = HIBYTE(HIWORD(i));
		rd->data[1] = LOBYTE(HIWORD(i));
		rd->data[2] = HIBYTE(LOWORD(i));
		rd->data[3] = LOBYTE(LOWORD(i));
2256
		break;
2257 2258

#ifndef WORDS_BIGENDIAN
2259
	default:
2260 2261 2262 2263 2264 2265
#endif
	case WRC_BO_LITTLE:
		rd->data[3] = HIBYTE(HIWORD(i));
		rd->data[2] = LOBYTE(HIWORD(i));
		rd->data[1] = HIBYTE(LOWORD(i));
		rd->data[0] = LOBYTE(LOWORD(i));
2266 2267
		break;
	}
2268 2269 2270
	return rd;
}

2271
static raw_data_t *str2raw_data(string_t *str)
Alexandre Julliard's avatar
Alexandre Julliard committed
2272 2273 2274 2275
{
	raw_data_t *rd;
	rd = new_raw_data();
	rd->size = str->size * (str->type == str_char ? 1 : 2);
2276
	rd->data = xmalloc(rd->size);
2277 2278 2279 2280 2281 2282 2283
	if(str->type == str_char)
		memcpy(rd->data, str->str.cstr, rd->size);
	else if(str->type == str_unicode)
	{
		int i;
		switch(byteorder)
		{
2284 2285
#ifdef WORDS_BIGENDIAN
		default:
2286
#endif
2287
		case WRC_BO_BIG:
2288
			for(i = 0; i < str->size; i++)
2289 2290 2291 2292
			{
				rd->data[2*i + 0] = HIBYTE((WORD)str->str.wstr[i]);
				rd->data[2*i + 1] = LOBYTE((WORD)str->str.wstr[i]);
			}
2293
			break;
2294
#ifndef WORDS_BIGENDIAN
2295
		default:
2296 2297
#endif
		case WRC_BO_LITTLE:
2298
			for(i = 0; i < str->size; i++)
2299 2300 2301 2302
			{
				rd->data[2*i + 1] = HIBYTE((WORD)str->str.wstr[i]);
				rd->data[2*i + 0] = LOBYTE((WORD)str->str.wstr[i]);
			}
2303 2304 2305 2306
			break;
		}
	}
	else
2307
		internal_error(__FILE__, __LINE__, "Invalid stringtype\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2308 2309 2310
	return rd;
}

2311
static raw_data_t *merge_raw_data(raw_data_t *r1, raw_data_t *r2)
Alexandre Julliard's avatar
Alexandre Julliard committed
2312 2313 2314 2315 2316 2317 2318
{
	r1->data = xrealloc(r1->data, r1->size + r2->size);
	memcpy(r1->data + r1->size, r2->data, r2->size);
	r1->size += r2->size;
	return r1;
}

2319
static raw_data_t *merge_raw_data_int(raw_data_t *r1, int i)
Alexandre Julliard's avatar
Alexandre Julliard committed
2320 2321 2322 2323 2324 2325 2326 2327
{
	raw_data_t *t = int2raw_data(i);
	merge_raw_data(r1, t);
	free(t->data);
	free(t);
	return r1;
}

2328
static raw_data_t *merge_raw_data_long(raw_data_t *r1, int i)
2329 2330 2331 2332 2333 2334 2335 2336
{
	raw_data_t *t = long2raw_data(i);
	merge_raw_data(r1, t);
	free(t->data);
	free(t);
	return r1;
}

2337
static raw_data_t *merge_raw_data_str(raw_data_t *r1, string_t *str)
Alexandre Julliard's avatar
Alexandre Julliard committed
2338 2339 2340 2341 2342 2343 2344 2345 2346
{
	raw_data_t *t = str2raw_data(str);
	merge_raw_data(r1, t);
	free(t->data);
	free(t);
	return r1;
}

/* Function the go back in a list to get the head */
2347
static menu_item_t *get_item_head(menu_item_t *p)
Alexandre Julliard's avatar
Alexandre Julliard committed
2348 2349 2350 2351 2352 2353 2354 2355
{
	if(!p)
		return NULL;
	while(p->prev)
		p = p->prev;
	return p;
}

2356
static resource_t *get_resource_head(resource_t *p)
Alexandre Julliard's avatar
Alexandre Julliard committed
2357 2358 2359 2360 2361 2362 2363 2364
{
	if(!p)
		return NULL;
	while(p->prev)
		p = p->prev;
	return p;
}

2365
static ver_block_t *get_ver_block_head(ver_block_t *p)
Alexandre Julliard's avatar
Alexandre Julliard committed
2366 2367 2368 2369 2370 2371 2372 2373
{
	if(!p)
		return NULL;
	while(p->prev)
		p = p->prev;
	return p;
}

2374
static ver_value_t *get_ver_value_head(ver_value_t *p)
Alexandre Julliard's avatar
Alexandre Julliard committed
2375 2376 2377 2378 2379 2380 2381 2382
{
	if(!p)
		return NULL;
	while(p->prev)
		p = p->prev;
	return p;
}

2383
static control_t *get_control_head(control_t *p)
Alexandre Julliard's avatar
Alexandre Julliard committed
2384 2385 2386 2387 2388 2389 2390 2391
{
	if(!p)
		return NULL;
	while(p->prev)
		p = p->prev;
	return p;
}

2392
static event_t *get_event_head(event_t *p)
Alexandre Julliard's avatar
Alexandre Julliard committed
2393 2394 2395 2396 2397 2398 2399 2400 2401
{
	if(!p)
		return NULL;
	while(p->prev)
		p = p->prev;
	return p;
}

/* Find a stringtable with given language */
2402
static stringtable_t *find_stringtable(lvc_t *lvc)
Alexandre Julliard's avatar
Alexandre Julliard committed
2403 2404 2405 2406 2407 2408
{
	stringtable_t *stt;

	assert(lvc != NULL);

	if(!lvc->language)
2409
		lvc->language = dup_language(currentlanguage);
Alexandre Julliard's avatar
Alexandre Julliard committed
2410 2411 2412 2413

	for(stt = sttres; stt; stt = stt->next)
	{
		if(stt->lvc.language->id == lvc->language->id
2414
		&& stt->lvc.language->sub == lvc->language->sub)
Alexandre Julliard's avatar
Alexandre Julliard committed
2415 2416 2417 2418 2419 2420 2421 2422
		{
			/* Found a table with the same language */
			/* The version and characteristics are now handled
			 * in the generation of the individual stringtables.
			 * This enables localized analysis.
			if((stt->lvc.version && lvc->version && *(stt->lvc.version) != *(lvc->version))
			|| (!stt->lvc.version && lvc->version)
			|| (stt->lvc.version && !lvc->version))
2423
				parser_warning("Stringtable's versions are not the same, using first definition\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2424 2425 2426 2427

			if((stt->lvc.characts && lvc->characts && *(stt->lvc.characts) != *(lvc->characts))
			|| (!stt->lvc.characts && lvc->characts)
			|| (stt->lvc.characts && !lvc->characts))
2428
				parser_warning("Stringtable's characteristics are not the same, using first definition\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2429 2430 2431 2432 2433 2434 2435 2436
			*/
			return stt;
		}
	}
	return NULL;
}

/* qsort sorting function for string table entries */
Eric Pouech's avatar
Eric Pouech committed
2437
#define STE(p)	((const stt_entry_t *)(p))
2438
static int sort_stt_entry(const void *e1, const void *e2)
Alexandre Julliard's avatar
Alexandre Julliard committed
2439 2440 2441 2442 2443
{
	return STE(e1)->id - STE(e2)->id;
}
#undef STE

2444
static resource_t *build_stt_resources(stringtable_t *stthead)
Alexandre Julliard's avatar
Alexandre Julliard committed
2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472
{
	stringtable_t *stt;
	stringtable_t *newstt;
	resource_t *rsc;
	resource_t *rsclist = NULL;
	resource_t *rsctail = NULL;
	int i;
	int j;
	DWORD andsum;
	DWORD orsum;
	characts_t *characts;
	version_t *version;

	if(!stthead)
		return NULL;

	/* For all languages defined */
	for(stt = stthead; stt; stt = stt->next)
	{
		assert(stt->nentries > 0);

		/* Sort the entries */
		if(stt->nentries > 1)
			qsort(stt->entries, stt->nentries, sizeof(stt->entries[0]), sort_stt_entry);

		for(i = 0; i < stt->nentries; )
		{
			newstt = new_stringtable(&stt->lvc);
2473
			newstt->entries = xmalloc(16 * sizeof(stt_entry_t));
2474
			memset( newstt->entries, 0, 16 * sizeof(stt_entry_t) );
Alexandre Julliard's avatar
Alexandre Julliard committed
2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504
			newstt->nentries = 16;
			newstt->idbase = stt->entries[i].id & ~0xf;
			for(j = 0; j < 16 && i < stt->nentries; j++)
			{
				if(stt->entries[i].id - newstt->idbase == j)
				{
					newstt->entries[j] = stt->entries[i];
					i++;
				}
			}
			andsum = ~0;
			orsum = 0;
			characts = NULL;
			version = NULL;
			/* Check individual memory options and get
			 * the first characteristics/version
			 */
			for(j = 0; j < 16; j++)
			{
				if(!newstt->entries[j].str)
					continue;
				andsum &= newstt->entries[j].memopt;
				orsum |= newstt->entries[j].memopt;
				if(!characts)
					characts = newstt->entries[j].characts;
				if(!version)
					version = newstt->entries[j].version;
			}
			if(andsum != orsum)
			{
2505
				warning("Stringtable's memory options are not equal (idbase: %d)\n", newstt->idbase);
Alexandre Julliard's avatar
Alexandre Julliard committed
2506 2507 2508 2509 2510 2511 2512
			}
			/* Check version and characteristics */
			for(j = 0; j < 16; j++)
			{
				if(characts
				&& newstt->entries[j].characts
				&& *newstt->entries[j].characts != *characts)
2513
					warning("Stringtable's characteristics are not the same (idbase: %d)\n", newstt->idbase);
Alexandre Julliard's avatar
Alexandre Julliard committed
2514 2515 2516
				if(version
				&& newstt->entries[j].version
				&& *newstt->entries[j].version != *version)
2517
					warning("Stringtable's versions are not the same (idbase: %d)\n", newstt->idbase);
Alexandre Julliard's avatar
Alexandre Julliard committed
2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543
			}
			rsc = new_resource(res_stt, newstt, newstt->memopt, newstt->lvc.language);
			rsc->name = new_name_id();
			rsc->name->type = name_ord;
			rsc->name->name.i_name = (newstt->idbase >> 4) + 1;
			rsc->memopt = andsum; /* Set to least common denominator */
			newstt->memopt = andsum;
			newstt->lvc.characts = characts;
			newstt->lvc.version = version;
			if(!rsclist)
			{
				rsclist = rsc;
				rsctail = rsc;
			}
			else
			{
				rsctail->next = rsc;
				rsc->prev = rsctail;
				rsctail = rsc;
			}
		}
	}
	return rsclist;
}


2544
static toolbar_item_t *ins_tlbr_button(toolbar_item_t *prev, toolbar_item_t *idrec)
2545 2546 2547 2548 2549 2550 2551 2552
{
	idrec->prev = prev;
	if(prev)
		prev->next = idrec;

	return idrec;
}

2553
static toolbar_item_t *get_tlbr_buttons_head(toolbar_item_t *p, int *nitems)
2554 2555 2556 2557 2558
{
	if(!p)
	{
		*nitems = 0;
		return NULL;
2559
	}
2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571

	*nitems = 1;

	while(p->prev)
	{
		(*nitems)++;
		p = p->prev;
	}

	return p;
}

2572 2573
static string_t *make_filename(string_t *str)
{
2574 2575
    if(str->type == str_char)
    {
2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587
	char *cptr;

	/* Remove escaped backslash and convert to forward */
	for(cptr = str->str.cstr; (cptr = strchr(cptr, '\\')) != NULL; cptr++)
	{
		if(cptr[1] == '\\')
		{
			memmove(cptr, cptr+1, strlen(cptr));
			str->size--;
		}
		*cptr = '/';
	}
2588 2589 2590 2591
    }
    else
    {
	WCHAR *wptr;
2592

2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604
	/* Remove escaped backslash and convert to forward */
	for(wptr = str->str.wstr; (wptr = strchrW(wptr, '\\')) != NULL; wptr++)
	{
		if(wptr[1] == '\\')
		{
			memmove(wptr, wptr+1, strlenW(wptr));
			str->size--;
		}
		*wptr = '/';
	}
    }
    return str;
2605 2606
}

2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630
/*
 * Process all resources to extract fonts and build
 * a fontdir resource.
 *
 * Note: MS' resource compiler (build 1472) does not
 * handle font resources with different languages.
 * The fontdir is generated in the last active language
 * and font identifiers must be unique across the entire
 * source.
 * This is not logical considering the localization
 * constraints of all other resource types. MS has,
 * most probably, never testet localized fonts. However,
 * using fontresources is rare, so it might not occur
 * in normal applications.
 * Wine does require better localization because a lot
 * of languages are coded into the same executable.
 * Therefore, I will generate fontdirs for *each*
 * localized set of fonts.
 */
static resource_t *build_fontdir(resource_t **fnt, int nfnt)
{
	static int once = 0;
	if(!once)
	{
2631
		warning("Need to parse fonts, not yet implemented (fnt: %p, nfnt: %d)\n", fnt, nfnt);
2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654
		once++;
	}
	return NULL;
}

static resource_t *build_fontdirs(resource_t *tail)
{
	resource_t *rsc;
	resource_t *lst = NULL;
	resource_t **fnt = NULL;	/* List of all fonts */
	int nfnt = 0;
	resource_t **fnd = NULL;	/* List of all fontdirs */
	int nfnd = 0;
	resource_t **lanfnt = NULL;
	int nlanfnt = 0;
	int i;
	name_id_t nid;
	string_t str;
	int fntleft;

	nid.type = name_str;
	nid.name.s_name = &str;
	str.type = str_char;
2655
	str.str.cstr = xstrdup("FONTDIR");
2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679
	str.size = 7;

	/* Extract all fonts and fontdirs */
	for(rsc = tail; rsc; rsc = rsc->prev)
	{
		if(rsc->type == res_fnt)
		{
			nfnt++;
			fnt = xrealloc(fnt, nfnt * sizeof(*fnt));
			fnt[nfnt-1] = rsc;
		}
		else if(rsc->type == res_fntdir)
		{
			nfnd++;
			fnd = xrealloc(fnd, nfnd * sizeof(*fnd));
			fnd[nfnd-1] = rsc;
		}
	}

	/* Verify the name of the present fontdirs */
	for(i = 0; i < nfnd; i++)
	{
		if(compare_name_id(&nid, fnd[i]->name))
		{
2680
			warning("User supplied FONTDIR entry has an invalid name '%s', ignored\n",
2681 2682 2683 2684 2685 2686 2687 2688 2689
				get_nameid_str(fnd[i]->name));
			fnd[i] = NULL;
		}
	}

	/* Sanity check */
	if(nfnt == 0)
	{
		if(nfnd != 0)
2690
			warning("Found %d FONTDIR entries without any fonts present\n", nfnd);
2691 2692 2693 2694 2695
		goto clean;
	}

	/* Copy space */
	lanfnt = xmalloc(nfnt * sizeof(*lanfnt));
2696
	memset( lanfnt, 0, nfnt * sizeof(*lanfnt));
2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724

	/* Get all fonts covered by fontdirs */
	for(i = 0; i < nfnd; i++)
	{
		int j;
		WORD cnt;
		int isswapped = 0;

		if(!fnd[i])
			continue;
		for(j = 0; j < nfnt; j++)
		{
			if(!fnt[j])
				continue;
			if(fnt[j]->lan->id == fnd[i]->lan->id && fnt[j]->lan->sub == fnd[i]->lan->sub)
			{
				lanfnt[nlanfnt] = fnt[j];
				nlanfnt++;
				fnt[j] = NULL;
			}
		}

		cnt = *(WORD *)fnd[i]->res.fnd->data->data;
		if(nlanfnt == cnt)
			isswapped = 0;
		else if(nlanfnt == BYTESWAP_WORD(cnt))
			isswapped = 1;
		else
2725
			error("FONTDIR for language %d,%d has wrong count (%d, expected %d)\n",
2726 2727 2728 2729 2730 2731 2732
				fnd[i]->lan->id, fnd[i]->lan->sub, cnt, nlanfnt);
#ifdef WORDS_BIGENDIAN
		if((byteorder == WRC_BO_LITTLE && !isswapped) || (byteorder != WRC_BO_LITTLE && isswapped))
#else
		if((byteorder == WRC_BO_BIG && !isswapped) || (byteorder != WRC_BO_BIG && isswapped))
#endif
		{
2733
			internal_error(__FILE__, __LINE__, "User supplied FONTDIR needs byteswapping\n");
2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776
		}
	}

	/* We now have fonts left where we need to make a fontdir resource */
	for(i = fntleft = 0; i < nfnt; i++)
	{
		if(fnt[i])
			fntleft++;
	}
	while(fntleft)
	{
		/* Get fonts of same language in lanfnt[] */
		for(i = nlanfnt = 0; i < nfnt; i++)
		{
			if(fnt[i])
			{
				if(!nlanfnt)
				{
			addlanfnt:
					lanfnt[nlanfnt] = fnt[i];
					nlanfnt++;
					fnt[i] = NULL;
					fntleft--;
				}
				else if(fnt[i]->lan->id == lanfnt[0]->lan->id && fnt[i]->lan->sub == lanfnt[0]->lan->sub)
					goto addlanfnt;
			}
		}
		/* and build a fontdir */
		rsc = build_fontdir(lanfnt, nlanfnt);
		if(rsc)
		{
			if(lst)
			{
				lst->next = rsc;
				rsc->prev = lst;
			}
			lst = rsc;
		}
	}

	free(lanfnt);
clean:
2777 2778
	free(fnt);
	free(fnd);
2779
	free(str.str.cstr);
2780 2781 2782
	return lst;
}

2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813
/*
 * This gets invoked to determine whether the next resource
 * is to be of a standard-type (e.g. bitmaps etc.), or should
 * be a user-type resource. This function is required because
 * there is the _possibility_ of a lookahead token in the
 * parser, which is generated from the "expr" state in the
 * "nameid" parsing.
 *
 * The general resource format is:
 * <identifier> <type> <flags> <resourcebody>
 *
 * The <identifier> can either be tIDENT or "expr". The latter
 * will always generate a lookahead, which is the <type> of the
 * resource to parse. Otherwise, we need to get a new token from
 * the scanner to determine the next step.
 *
 * The problem arrises when <type> is numerical. This case should
 * map onto default resource-types and be parsed as such instead
 * of being mapped onto user-type resources.
 *
 * The trick lies in the fact that yacc (bison) doesn't care about
 * intermediate changes of the lookahead while reducing a rule. We
 * simply replace the lookahead with a token that will result in
 * a shift to the appropriate rule for the specific resource-type.
 */
static int rsrcid_to_token(int lookahead)
{
	int token;

	/* Get a token if we don't have one yet */
	if(lookahead == YYEMPTY)
2814
		lookahead = yylex();
2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868

	/* Only numbers are possibly interesting */
	switch(lookahead)
	{
	case tNUMBER:
	case tLNUMBER:
		break;
	default:
		return lookahead;
	}

	token = lookahead;

	switch(yylval.num)
	{
	case WRC_RT_CURSOR:
		token = tCURSOR;
		break;
	case WRC_RT_ICON:
		token = tICON;
		break;
	case WRC_RT_BITMAP:
		token = tBITMAP;
		break;
	case WRC_RT_FONT:
		token = tFONT;
		break;
	case WRC_RT_FONTDIR:
		token = tFONTDIR;
		break;
	case WRC_RT_RCDATA:
		token = tRCDATA;
		break;
	case WRC_RT_MESSAGETABLE:
		token = tMESSAGETABLE;
		break;
	case WRC_RT_DLGINIT:
		token = tDLGINIT;
		break;
	case WRC_RT_ACCELERATOR:
		token = tACCELERATORS;
		break;
	case WRC_RT_MENU:
		token = tMENU;
		break;
	case WRC_RT_DIALOG:
		token = tDIALOG;
		break;
	case WRC_RT_VERSION:
		token = tVERSIONINFO;
		break;
	case WRC_RT_TOOLBAR:
		token = tTOOLBAR;
		break;
2869 2870 2871
	case WRC_RT_HTML:
		token = tHTML;
		break;
2872 2873 2874 2875 2876 2877 2878 2879

	case WRC_RT_STRING:
		break;

	case WRC_RT_ANICURSOR:
	case WRC_RT_ANIICON:
	case WRC_RT_GROUP_CURSOR:
	case WRC_RT_GROUP_ICON:
2880
		parser_warning("Usertype uses reserved type ID %d, which is auto-generated\n", yylval.num);
2881 2882 2883 2884 2885
		return lookahead;

	case WRC_RT_DLGINCLUDE:
	case WRC_RT_PLUGPLAY:
	case WRC_RT_VXD:
2886
		parser_warning("Usertype uses reserved type ID %d, which is not supported by wrc yet\n", yylval.num);
2887 2888 2889 2890
	default:
		return lookahead;
	}

2891
	return token;
2892
}