/*****

      $Source: d:\gunther\source\grc/RCS/rccparse.y,v $
      $Author: gunther $
      $Date: 1995/12/29 23:49:21 $
      $Revision: 1.5 $

	Changed by: Fred Kiefer (kiefer@isys.de) 1996/6/2

 *****/

%{
#include <string.h>
#include "port.h"

#include "resnt.h"
#include "yystype.h"
#include "rcutils.h"
#include "rcompile.h"
#include "wstring.h"


int lines;
char currentFile[MAX_PATH];
ResourceTail globalTail = { 0, 0, 0x409, 0, 0 };

/* #define YYDEBUG 1 */
/* #define YYINITDEPTH 50 */

#define MAKESTYLE(style, default) (((default) & ~(style.negative)) | (style.positive))

#define CONTROL_DEFAULT WS_CHILD | WS_VISIBLE
#define AUTO3STATE_DEFAULT BS_AUTO3STATE | WS_TABSTOP | CONTROL_DEFAULT
#define AUTOCHECKBOX_DEFAULT BS_AUTOCHECKBOX | WS_TABSTOP | CONTROL_DEFAULT
#define AUTORADIOBUTTON_DEFAULT BS_AUTORADIOBUTTON | CONTROL_DEFAULT
#define CHECKBOX_DEFAULT BS_CHECKBOX | WS_TABSTOP | CONTROL_DEFAULT
#define COMBOBOX_DEFAULT WS_TABSTOP | CONTROL_DEFAULT
#define CTEXT_DEFAULT SS_CENTER | WS_GROUP | CONTROL_DEFAULT
#define DEFPUSHBUTTON_DEFAULT BS_DEFPUSHBUTTON | WS_TABSTOP  | CONTROL_DEFAULT
#define EDITTEXT_DEFAULT ES_LEFT | WS_BORDER | WS_TABSTOP | CONTROL_DEFAULT
#define GROUPBOX_DEFAULT BS_GROUPBOX | CONTROL_DEFAULT
#define ICON_DEFAULT SS_ICON | CONTROL_DEFAULT
#define LISTBOX_DEFAULT LBS_NOTIFY | WS_BORDER | CONTROL_DEFAULT
#define LTEXT_DEFAULT SS_LEFT | WS_GROUP | CONTROL_DEFAULT
#define PUSHBUTTON_DEFAULT BS_PUSHBUTTON | WS_TABSTOP | CONTROL_DEFAULT
#define RADIOBUTTON_DEFAULT BS_RADIOBUTTON | WS_TABSTOP | CONTROL_DEFAULT
#define RTEXT_DEFAULT SS_RIGHT | WS_GROUP | CONTROL_DEFAULT
#define SCROLLBAR_DEFAULT SBS_HORZ | CONTROL_DEFAULT
#define STATE3_DEFAULT BS_3STATE | WS_TABSTOP | CONTROL_DEFAULT


/* forword declarations */
void getFileInfo(char *filename, int line);
struct_control *CONTROLWITHTITLE(char *name, int id, int x, int y, int cx, int cy,
                       int type, unsigned long style, unsigned long exstyle);
struct_control *CONTROLWITHTYPE(char *name, int id, int x, int y, int cx, int cy,
                       char *type, unsigned long style, unsigned long exstyle);
struct_control *CONTROLWITHID(int name, int id, int x, int y, int cx, int cy,
                       int type, unsigned long style, unsigned long exstyle);
int known_type(char *type);
rcdata_entry *new_rc_entry(void *data, int size);
%}

%token WHITESPACE NUMBER STRING QUOTEDSTRING ACCELERATORS AUTO3STATE AUTOCHECKBOX
%token AUTORADIOBUTTON BEG BITMAP CAPTION CHARACTERISTICS CHECKBOX CLASS COMBOBOX
%token CONTROL CTEXT CURSOR DEFPUSHBUTTON DIALOG DIALOGEX EDITTEXT END EXSTYLE FONT
%token GROUPBOX ICON LANGUAGE LISTBOX LTEXT MENUITEM MENUEX MENU MESSAGETABLE NOT POPUP
%token PUSHBOX PUSHBUTTON RADIOBUTTON RCDATA RTEXT SCROLLBAR STATE3 STRINGTABLE STYLE
%token VERSION VERSIONINFO DLGINCLUDE
%token MEMFLAG SEPARATOR MENUFLAG ALT SHIFT NOINVERT ASCII VIRTKEY
%token FILEVERSION PRODUCTVERSION FILEFLAGS FILEFLAGSMASK FILEOS
%token FILETYPE FILESUBTYPE BLOCK VALUE TOOLBAR BUTTON

%union     {
	struct_dialog *dialog;
	struct_control *control;
	rcdata_entry *rcdata;
	version_entry *vsdata;
	struct_flags flags;
	ResourceTail option;
	ACCELTABLEENTRY accel_entry;
	DLGFONT font;
	VS_FIXEDFILEINFO vsfixed;
	unsigned long file_version[2];
	file_info finfo;
	node *list;
	char string[MAX_RES_STRING];
	wchar_t ustring[MAX_RES_STRING];
	unsigned int value;
}

%type <value> NUMBER MEMFLAG MENUFLAG
%type <string> QUOTEDSTRING STRING

%type <control> control 
%type <dialog> dialog_options  
%type <option> default_options
%type <rcdata> rc_entry
%type <flags> styleflag styleflags
%type <accel_entry> acc_entry acc_event 
%type <font> font_stmnt 
%type <finfo> file 
%type <vsfixed> fixed_info
%type <vsdata> block_entry value_stmt block_stmt
%type <file_version> file_version
%type <list> controls acc_entries string_entries menuitems rc_entries 
%type <list> block_entries block_stmts toolbar_entries
%type <string> file_name control_title
%type <value> characteristics_stmnt exstyle_stmnt style_stmnt language_stmnt 
%type <value> version_stmnt acc_option acc_options mflag memflags 
%type <value> menuitem_flags opt_exstyle
%type <ustring> id_or_name class_stmnt menu_stmnt caption_stmnt

%start input

%%

input:  /* empty */ 
	| input '\n'        {}
	| input fileinfo    {}
	| input bitmapres   { verbose(("compiling bitmap\n")); }
	| input iconres     { verbose(("compiling icon\n")); }
	| input cursorres   { verbose(("compiling cursor\n")); }
	| input dialogres   { verbose(("compiling dialog\n"));}
	| input menures     { verbose(("compiling menu\n"));}
	| input accelres    { verbose(("compiling accelerators\n"));}
	| input language_stmnt      { globalTail.LanguageId = $2; }
	| input version_stmnt       { globalTail.Version = $2; }
	| input stringres   { verbose(("compiling stringtable\n"));}
	| input fontres     { verbose(("compiling font\n"));}
	| input version_info   { verbose(("compiling version info\n"));}
	| input toolbarres  { verbose(("compiling toolbarres\n"));}
	| input rcdata      { verbose(("compiling rcdata\n"));}
	| input dlginclude  { verbose(("compiling dlginclude\n"));}
	| input userres     { verbose(("compiling userres\n"));}
	| error '\n'        { /* ignore some C declarations in header files */ yyerrok; }
;

fileinfo: file '\n'
	{
		getFileInfo($1.fname, $1.fline);
		/* If we are in a header file, we could skip on to the next fileinfo statement */
	}
;

file: '#' NUMBER QUOTEDSTRING
	{
		debug(("found fileinfo "));

		strcpy($$.fname, $3);
		$$.fline = $2;
	}
	|  file NUMBER     
	{ 
		$$ = $1;
	}
;

file_name: QUOTEDSTRING
	{
		expand_string($$, $1);
	}
	| STRING
	{
		strcpy($$, $1);
	}
	| STRING '.' STRING
	{
		/* This makes it possibel to have simple file names without
			quotes, but for file names with "\" you still have to use
			quotationmarks */
		if (strlen($1) + 1 + strlen($3) > MAX_RES_STRING)
		{
			fprintf(stderr, "Filename too long %s.%s", $1, $3);
			strcpy($$, $1);
		}
		else
		{
			strcpy($$, $1);
			strcat($$, ".");
			strcat($$, $3);
		}
	}
;

bitmapres: id_or_name BITMAP file_name '\n'
	{
		getBitmap($1, MOVEABLE | PURE, &globalTail, $3);
	}
	| id_or_name BITMAP memflags file_name '\n'
	{
	 	getBitmap($1, $3 | MOVEABLE | PURE, &globalTail, $4);
	}
	| id_or_name BITMAP error '\n'
	{
		err_msg(GRC_err_bmp_filename_expected);
		yyerrok;
	}
;

iconres: id_or_name ICON file_name '\n'
	{
		getIcon($1, DISCARDABLE | MOVEABLE, &globalTail, $3);
	}
	| id_or_name ICON memflags file_name '\n'
	{
		/* Dont ask me why MS does this. They probably dont know it themself. */
		if ($3 & DISCARDABLE) { $3 |= PURE; }
		getIcon($1, $3 | DISCARDABLE | MOVEABLE, &globalTail, $4);
	}
	| id_or_name ICON error '\n'
	{ 
		err_msg(GRC_err_ico_filename_expected);
		yyerrok;
	}
;

cursorres: id_or_name CURSOR file_name '\n'
	{ 
		getCursor($1, DISCARDABLE | MOVEABLE, &globalTail, $3);
	}
	| id_or_name CURSOR memflags file_name '\n'
	{
		getCursor($1, $3 | MOVEABLE | PURE, &globalTail, $4);
	}
	| id_or_name CURSOR error '\n'
	{
		err_msg(GRC_err_ico_filename_expected); 
		yyerrok;
	}
;

fontres: id_or_name FONT file_name '\n'
	{ 
		getFont($1, DISCARDABLE, &globalTail, $3);
		yyerror("Unsupported statement: Font Resource");
	}
	| id_or_name FONT memflags file_name '\n'       
	{ 
		getFont($1, $3, &globalTail, $4); 
		yyerror("Unsupported statement: Font Resource");
	}
	| id_or_name FONT error '\n'
	{ 
		err_msg(GRC_err_font_filename_expected); 
		yyerrok; 
	}
;

dialogres: id_or_name DIALOG memflags NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n' dialog_options BEG '\n' controls END
	{
		getDialog($1, $3 | PURE | MOVEABLE, $4, $6, $8, $10, $12, $15);
	}
	| id_or_name DIALOG NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n' dialog_options BEG '\n' controls END
	{
		getDialog($1, DISCARDABLE | PURE | MOVEABLE, $3, $5, $7, $9, $11, $14);
	}
	| id_or_name DIALOG error END         
	{ 
		err_msg(GRC_err_dlg_invalid); 
		yyerrok; 
	}
;

menures: id_or_name MENU memflags '\n' default_options BEG '\n' menuitems END
	{
		getMenu($1, $3 | PURE | MOVEABLE, &$5, $8);
	}
	| id_or_name MENU '\n' default_options BEG '\n' menuitems END
	{
		getMenu($1, DISCARDABLE | PURE | MOVEABLE, &$4, $7);
	}
	| id_or_name MENU error END           
	{ 
		err_msg(GRC_err_menu_invalid);
		yyerrok;
	}
;

stringres: STRINGTABLE memflags '\n' default_options BEG '\n' string_entries END
	{
		addTable($2 | PURE | MOVEABLE, &$4, $7);
	}
	|  STRINGTABLE '\n' default_options BEG '\n' string_entries END
	{
		addTable(DISCARDABLE | PURE | MOVEABLE, &$3, $6);
	}
	|  STRINGTABLE error END
	{ 
		err_msg(GRC_err_string_invalid); 
		yyerrok; 
	}
;


accelres: id_or_name ACCELERATORS memflags '\n' default_options BEG '\n' acc_entries END
	{
		getAccelerators($1, $3 | PURE | MOVEABLE, &$5, $8);
	}
	| id_or_name ACCELERATORS '\n' default_options BEG '\n' acc_entries END
	{
		getAccelerators($1, PURE | MOVEABLE, &$4, $7);
	}
	| id_or_name ACCELERATORS error END
	{ 
		err_msg(GRC_err_invalid_accelerator); 
		yyerrok; 
	}
;


string_entries:     /* empty */
	{
		$$ = list_new();
	}
	| string_entries '\n'
	{
		$$ = $1;
	}
	| string_entries NUMBER OPT_SEP QUOTEDSTRING '\n'
	{
		stringEntry *entry = (stringEntry *) xmalloc(sizeof(stringEntry));
		int len = expand_string($4, $4);

		entry->pos = $2 & 0x000F;
		entry->block = (((unsigned short) $2) >> 4) + 1;
		entry->string = (wchar_t *) xmalloc((len + 2) * sizeof(wchar_t));
		ansi2uni(&entry->string[1], $4);
		entry->string[0] = len;
		$$ = $1;
		list_add($$, (void *)entry);
	}
	| string_entries error '\n'       
	{ 
		err_msg(GRC_err_strtable_invalid);
		yyerrok; 
	}
;

caption_stmnt:  CAPTION QUOTEDSTRING '\n'
	{
		expand_string($2, $2);
		ansi2uni($$, $2);
	}
;

characteristics_stmnt: CHARACTERISTICS NUMBER '\n'
	{
		$$ = $2;
	}
;

class_stmnt: CLASS STRING '\n'
	{
		ansi2uni($$, $2);
	}
	| CLASS NUMBER '\n'
	{
		$$[0] = INVAL_WCHAR;
		$$[1] = $2;
	}
;

language_stmnt: LANGUAGE NUMBER ',' NUMBER '\n'
	{
		$$ = MAKELANGID($2, $4);
	}
;

style_stmnt: STYLE styleflags '\n'
	{
		/* We only hand on the explizit flags */
		$$ = $2.positive;
	}
;

exstyle_stmnt: EXSTYLE '=' styleflags '\n'
	{
		/* We only hand on the explizit flags */
		$$ = $3.positive;
	}
;

version_stmnt: VERSION NUMBER '\n'
	{
		$$ = $2;
	}
;

font_stmnt: FONT NUMBER ',' QUOTEDSTRING '\n'
	{
		$$.PointSize = $2;
		ansi2uni($$.TypefaceName, $4);
	}
;

menu_stmnt: MENU STRING '\n'
	{
		ansi2uni($$, $2);
	}
	| MENU NUMBER '\n'
	{
		$$[0] = INVAL_WCHAR;
		$$[1] = $2;
	}
;

default_options: /* empty */
	{
		memcpy(&$$, &globalTail, sizeof(globalTail));
	}
	| default_options '\n'
	{
		memcpy(&$$, &$1, sizeof(globalTail));
	}
	| default_options characteristics_stmnt
	{
		memcpy(&$$, &$1, sizeof(globalTail));
		$$.Characteristics = $2;
	}
	| default_options language_stmnt
	{
		memcpy(&$$, &$1, sizeof(globalTail));
		$$.LanguageId = $2;
	}
	| default_options version_stmnt
	{
		memcpy(&$$, &$1, sizeof(globalTail));
		$$.Version = $2;
	}
	| default_options error '\n'
	{
		err_msg(GRC_err_invalid_stmnt);
		yyerrok;
	}
;

dialog_options:     /* empty */
	{
		$$ = (struct_dialog *) xmalloc(sizeof(struct_dialog));
		memset($$, 0, sizeof(struct_dialog));
		memcpy(&$$->tail, &globalTail, sizeof(globalTail));
	}
	| dialog_options '\n'
	{
		$$ = $1;
	}
	| dialog_options caption_stmnt
	{
		$$ = $1;
		memcpy($$->nameID, $2, getIDlength($2));
		$$->style |= WS_CAPTION;
	}
	| dialog_options characteristics_stmnt
	{
		$$ = $1;
		$$->tail.Characteristics = $2;
	}
	| dialog_options class_stmnt
	{
		$$ = $1;
		memcpy($$->typeID, $2, getIDlength($2));
	}
	| dialog_options language_stmnt
	{
		$$ = $1;
		$$->tail.LanguageId = $2;
	}
	| dialog_options style_stmnt
	{
		$$ = $1;
		$$->style |= $2;
	}
	| dialog_options exstyle_stmnt
	{
		$$ = $1;
		$$->dwExtendedStyle = $2;
	}
	| dialog_options version_stmnt
	{
		$$ = $1;
		$$->tail.Version = $2;
	}
	| dialog_options font_stmnt
	{
		$$ = $1;
		$$->style |= DS_SETFONT;
		memcpy(&$$->font, &$2, sizeof(DLGFONT));
	}
	| dialog_options menu_stmnt
	{
		$$ = $1;
		memcpy($$->menuID, $2, getIDlength($2));
	}
	| dialog_options error '\n'
	{
		err_msg(GRC_err_invalid_stmnt); 
		yyerrok;
	}
;


control: AUTO3STATE QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			MAKESTYLE($14, AUTO3STATE_DEFAULT), $15);
	}
	| AUTO3STATE QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			AUTO3STATE_DEFAULT, 0);
	}
	| AUTOCHECKBOX QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			MAKESTYLE($14, AUTOCHECKBOX_DEFAULT), $15);
	}
	| AUTOCHECKBOX QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			AUTOCHECKBOX_DEFAULT, 0);
	}
	| AUTORADIOBUTTON QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			MAKESTYLE($14, AUTORADIOBUTTON_DEFAULT), $15);
	}
	| AUTORADIOBUTTON QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			AUTORADIOBUTTON_DEFAULT, 0);
	}
	| CHECKBOX QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			MAKESTYLE($14, CHECKBOX_DEFAULT), $15);
	}
	| CHECKBOX QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			CHECKBOX_DEFAULT, 0);
	}
	| COMBOBOX control_title NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $3, $5, $7, $9, $11, CTL_COMBOBOX, 
			MAKESTYLE($13, COMBOBOX_DEFAULT),  $14);
	}
	| COMBOBOX control_title NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $3, $5, $7, $9, $11, CTL_COMBOBOX, 
			CBS_SIMPLE | COMBOBOX_DEFAULT, 0);
	}
	| CONTROL QUOTEDSTRING OPT_SEP NUMBER SEP QUOTEDSTRING SEP styleflags SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER opt_exstyle '\n'
	{
		int type = known_type($6);

		if (type)
		{ 
			$$ = CONTROLWITHTITLE($2, $4, $10, $12, $14, $16, type, 
					MAKESTYLE($8, CONTROL_DEFAULT), $17);
		}
		else
		{
			$$ = CONTROLWITHTYPE($2, $4, $10, $12, $14, $16, $6, 
					MAKESTYLE($8, CONTROL_DEFAULT), $17);
		}
	}
	| CONTROL QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP styleflags SEP NUMBER SEP NUMBER SEP NUMBER  SEP NUMBER opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $10, $12, $14, $16, $6, 
			MAKESTYLE($8, CONTROL_DEFAULT), $17);
	}
	| CTEXT QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_STATIC, 
			MAKESTYLE($14, CTEXT_DEFAULT), $15);
	}
	| CTEXT QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_STATIC, 
			CTEXT_DEFAULT, 0);
	}
	| DEFPUSHBUTTON QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			MAKESTYLE($14, DEFPUSHBUTTON_DEFAULT), $15);
	}
	| DEFPUSHBUTTON QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			DEFPUSHBUTTON_DEFAULT, 0);
	}
	| EDITTEXT control_title NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $3, $5, $7, $9, $11, CTL_EDIT, 
			MAKESTYLE($13, EDITTEXT_DEFAULT), $14);
	}
	| EDITTEXT control_title NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $3, $5, $7, $9, $11, CTL_EDIT, 
			EDITTEXT_DEFAULT, 0);
	}
	| GROUPBOX QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			MAKESTYLE($14, GROUPBOX_DEFAULT), $15);
	}
	| GROUPBOX QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			GROUPBOX_DEFAULT, 0);
	}
	| ICON QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_STATIC, 
			MAKESTYLE($14, ICON_DEFAULT), $15);
	}
	| ICON QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_STATIC, 
			ICON_DEFAULT, 0);
	}
	| ICON NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		/* Icons can also have the id of an icon resource in the resources file */ 
		$$ = CONTROLWITHID($2, $4, $6, $8, $10, $12, CTL_STATIC, 
			MAKESTYLE($14, ICON_DEFAULT), $15);
	}
	| ICON NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHID($2, $4, $6, $8, $10, $12, CTL_STATIC, 
			ICON_DEFAULT, 0);
	}
	| LISTBOX control_title NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $3, $5, $7, $9, $11, CTL_LISTBOX, 
			MAKESTYLE($13, LISTBOX_DEFAULT), $14);
	}
	| LISTBOX control_title NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $3, $5, $7, $9, $11, CTL_LISTBOX, 
			LISTBOX_DEFAULT, 0);
	}
	| LTEXT QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_STATIC, 
			MAKESTYLE($14, LTEXT_DEFAULT), $15);
	}
	| LTEXT QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_STATIC, 
			LTEXT_DEFAULT, 0);
	}
	| PUSHBOX QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		/* Use PUSHBUTTON instead */
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			MAKESTYLE($14, PUSHBUTTON_DEFAULT), $15);
	}
	| PUSHBOX QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			PUSHBUTTON_DEFAULT, 0);
	}
	| PUSHBUTTON QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			MAKESTYLE($14, PUSHBUTTON_DEFAULT), $15);
	}
	| PUSHBUTTON QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			PUSHBUTTON_DEFAULT, 0);
	}
	| RADIOBUTTON QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			MAKESTYLE($14, RADIOBUTTON_DEFAULT), $15);
	}
	| RADIOBUTTON QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			RADIOBUTTON_DEFAULT, 0);
	}
	| RTEXT QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_STATIC, 
			MAKESTYLE($14, RTEXT_DEFAULT), $15);
	}
	| RTEXT QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_STATIC, 
			RTEXT_DEFAULT, 0);
	}
	| SCROLLBAR control_title NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $3, $5, $7, $9, $11, CTL_SCROLLBAR, 
			MAKESTYLE($13, SCROLLBAR_DEFAULT), $14);
	}
	| SCROLLBAR control_title NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $3, $5, $7, $9, $11, CTL_SCROLLBAR, 
			SCROLLBAR_DEFAULT, 0);
	}
	| STATE3 QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP styleflags opt_exstyle '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
			MAKESTYLE($14, STATE3_DEFAULT), $15);
	}
	| STATE3 QUOTEDSTRING OPT_SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER SEP NUMBER '\n'
	{
		$$ = CONTROLWITHTITLE($2, $4, $6, $8, $10, $12, CTL_BUTTON, 
		STATE3_DEFAULT, 0);
	}
;


controls: control
	{
 		$$ = list_new();
 		list_add($$, $1);
 	}
	| controls control
	{
		$$ = $1;
		list_add($$, $2);
	}
	| controls '\n'
	{
		$$ = $1;
	}
	| controls error '\n'      
	{ 
		err_msg(GRC_err_dlg_ctl_expected); 
		yyerrok; 
	}
;

/* Optional title string for control, followed by an optional seperator */
control_title: /* empty*/
	{
		/* No title for this control */
		$$[0] = '\0';
	}
	| QUOTEDSTRING
	{
		strcpy($$, $1);
	}
	| QUOTEDSTRING SEP
	{
		strcpy($$, $1);
	}
;


menuitems:      /* empty */
	{
		$$ = list_new();
	}
	| menuitems '\n'
	{
		$$ = $1;
	}
	| menuitems POPUP QUOTEDSTRING SEP menuitem_flags '\n' BEG '\n' menuitems END
	{
		menuItem *popup = (menuItem *) xmalloc(sizeof(menuItem));
		popup->items = $9;
		popup->flags = MENUFLAG_POPUP | $5;
		expand_string($3, $3);
		ansi2uni(popup->title, $3);
		$$ = $1;
		list_add($$, (void *)popup);
	}
	| menuitems POPUP QUOTEDSTRING '\n' BEG '\n' menuitems END
	{
		menuItem *popup = (menuItem *) xmalloc(sizeof(menuItem));
		popup->items = $7;
		popup->flags = MENUFLAG_POPUP;
		expand_string($3, $3);
		ansi2uni(popup->title, $3);
		$$ = $1;
		list_add($$, (void *)popup);
	}
	| menuitems MENUITEM QUOTEDSTRING SEP NUMBER SEP menuitem_flags '\n'
	{
		menuItem *item = (menuItem *) xmalloc(sizeof(menuItem));
		item->items = NULL;
		item->flags = $7;
		item->id = $5;
		expand_string($3, $3);
		ansi2uni(item->title, $3);                    
		$$ = $1;
		list_add($$, (void *)item);
	}
	| menuitems MENUITEM QUOTEDSTRING SEP NUMBER '\n'
	{
		menuItem *item = (menuItem *) xmalloc(sizeof(menuItem));
		item->items = NULL;
		item->flags = 0;
		item->id = $5;
		expand_string($3, $3);
		ansi2uni(item->title, $3);                    
		$$ = $1;
		list_add($$, (void *)item);
	}
	| menuitems MENUITEM SEPARATOR '\n'
	{
		menuItem *item = (menuItem *) xmalloc(sizeof(menuItem));
		item->items = NULL;
		item->flags = MENUFLAG_SEPARATOR;
		item->id = 0;
		ansi2uni(item->title, "");                    
		$$ = $1;
		list_add($$, (void *)item);
	}
	| menuitems error '\n'     
	{ 
		err_msg(GRC_err_menuitem_invalid); 
		yyerrok; 
	}
;

/* (empty) list of entries in an accelarator table */
acc_entries:      /* empty */
	{
		$$ = list_new();
	}
	| acc_entries '\n'
	{
		$$ =$1;
	}
	| acc_entries acc_entry 
	{
		ACCELTABLEENTRY*entry = (ACCELTABLEENTRY*) xmalloc(sizeof(ACCELTABLEENTRY));

		$$ = $1;
		*entry = $2;
		list_add($$, (void *)entry);
	}
	| acc_entries error '\n'
	{
		err_msg(GRC_err_invalid_accelerator);
		yyerrok;
	}
;


acc_entry: acc_event SEP NUMBER '\n'
	{
		memcpy(&$$, &$1, sizeof(ACCELTABLEENTRY));
		$$.wId = $3;
	}
	| acc_event SEP NUMBER SEP acc_options '\n'
	{
		memcpy(&$$, &$1, sizeof(ACCELTABLEENTRY));
		$$.fFlags = $$.fFlags | $5;
		$$.wId = $3;
	}
;

acc_option: NOINVERT      { $$ = ACC_NOINVERT; }
	| SHIFT         { $$ = ACC_SHIFT; }
	| ALT           { $$ = ACC_ALT; }
	| CONTROL       { $$ = ACC_CONTROL; }
	| VIRTKEY { $$ = ACC_VIRTKEY; }
	| ASCII { $$ = 0; }
;

acc_options: acc_option      
	{ 
		$$ = $1; 
	}
	| acc_options SEP acc_option
	{
		$$ = $1 | $3;
	}
;

acc_event: QUOTEDSTRING
	{
		$$.padding = 0;
		expand_string($1, $1);
		if(strlen($1) != 1){
			if ((strlen($1) == 2) && ($1[0] == '^')){
				$$.wAscii = $1[1];
				$$.fFlags = ACC_CONTROL;
			}
			else
				err_msg(GRC_err_one_char);
		}
		else 	
			$$.wAscii = $1[0];
			$$.fFlags = 0;
	}
	| STRING
	{
		if(strlen($1) != 1)
			err_msg(GRC_err_one_char);

		$$.padding = 0;
		$$.wAscii = $1[0];
		$$.fFlags = 0;
	}
	| NUMBER
	{
		$$.padding = 0;
		$$.wAscii = $1;
		$$.fFlags = 0;
	}
;

menuitem_flags: MENUFLAG      { $$ = $1; }
	| BITMAP                  { $$ = MENUFLAG_BITMAP; }
	| NUMBER                  { $$ = $1; }
	| menuitem_flags MENUFLAG { $$ = $1 | $2; }
	| menuitem_flags BITMAP   { $$ = $1 | MENUFLAG_BITMAP; }
	| menuitem_flags NUMBER   { $$ = $1 | $2; }
;

mflag: MEMFLAG {$$ = $1}
	| NUMBER {$$ = $1}
;

memflags: mflag                { $$ = $1; }
	| memflags mflag       { $$ = $1 | $2; }
;

styleflag: NUMBER 
	{
		$$.positive = $1;
		$$.negative = 0;
	}
	| NOT NUMBER 	
	{ 
		$$.negative = $2;
		$$.positive = 0;
	}
;

styleflags: styleflag 
	{ 
		$$ = $1; 
	}
	| '(' styleflags ')' 
	{ 
		$$ = $2;
	}
	| styleflags '|' styleflag 
	{ 
		$$.positive = $1.positive | $3.positive;
		$$.negative = $1.negative | $3.negative;
	}
	| styleflags '|' '\n' styleflag 
	{ 
		$$.positive = $1.positive | $4.positive;
		$$.negative = $1.negative | $4.negative;
	}
;             
             
opt_exstyle: /* empty */
	{
		$$ = 0;
	}
	| SEP styleflags
	{
		$$ = $2.positive;
	}
;

id_or_name:	NUMBER
	{
		$$[0] = INVAL_WCHAR;
		$$[1] = (wchar_t)$1;
	}
	| STRING
	{
		ansi2uni($$, strupr($1)); 
	}
;

SEP: ','
	| ',' '\n'
;

OPT_SEP: /* empty */ 
	| ','
	| ',' '\n'
;

version_info: NUMBER VERSIONINFO fixed_info BEG '\n' block_stmts END
	{
		int len;
		int len2 = sizeof(VS_FIXEDFILEINFO);
		wchar_t id[2] = {INVAL_WCHAR, 1}; 
		char name[] = "VS_VERSION_INFO";
		version_entry *vs;

		len = (strlen(name) + 1) * sizeof(wchar_t);
		
		vs = (version_entry *)xmalloc(sizeof(version_entry) + len + len2);
		vs->wValueLength = len2;
		vs->szKey = (wchar_t *)(vs + 1);
		ansi2uni(vs->szKey, name); 
		vs->wType = 0;
		vs->lpValue = vs->szKey + strlen(name) + 1;
		memcpy(vs->lpValue, &$3, sizeof(VS_FIXEDFILEINFO));
		vs->entries = $6;

		getVersioninfo(id, MOVEABLE | PURE, &globalTail, vs)
		/*yyerror("Unsupported statement VERSIONINFO");*/
	}
	| NUMBER VERSIONINFO error END
	{ 
		err_msg(GRC_err_invalid_versioninfo); 
		yyerrok; 
	}
;

fixed_info: /*empty */
	{
		memset(&$$, 0, sizeof(VS_FIXEDFILEINFO));
		$$.dwSignature = 0xfeef04bd;
		$$.dwStrucVersion = 0x10000;
		$$.dwFileDateMS = 0;
		$$.dwFileDateLS = 0;
	}
	| fixed_info '\n'
	{
		$$ = $1;
	}
	| fixed_info FILEVERSION file_version '\n'
	{
		$$ = $1;
		$$.dwFileVersionMS = $3[0];
		$$.dwFileVersionLS = $3[1]
	}
	| fixed_info PRODUCTVERSION file_version '\n'
	{
		$$ = $1;
		$$.dwProductVersionMS = $3[0];
		$$.dwProductVersionLS = $3[1]
	}
	| fixed_info FILEFLAGS styleflags '\n'
	{
		$$ = $1;
		$$.dwFileFlags = $3.positive;
	}
	| fixed_info FILEFLAGSMASK styleflags '\n'
	{
		$$ = $1;
		$$.dwFileFlagsMask = $3.positive;
	}
	| fixed_info FILEOS styleflags '\n'
	{
		$$ = $1;
		$$.dwFileOS = $3.positive;
	}
	| fixed_info FILETYPE styleflags '\n'
	{
		$$ = $1;
		$$.dwFileType = $3.positive;
	}
	| fixed_info FILESUBTYPE styleflags '\n'
	{
		$$ = $1;
		$$.dwFileSubtype = $3.positive;
	}
;

file_version: NUMBER SEP NUMBER SEP NUMBER SEP NUMBER 
	{
		$$[0] = ((unsigned long)$1 << 16) | $3;
		$$[1] = ((unsigned long)$5 << 16) | $7;
	}
	| NUMBER SEP NUMBER SEP NUMBER 
	{
		$$[0] = ((unsigned long)$1 << 16) | $3;
		$$[1] = ((unsigned long)$5 << 16);
	}
	| NUMBER SEP NUMBER 
	{
		$$[0] = ((unsigned long)$1 << 16) | $3;
		$$[1] = 0;
	}
	| NUMBER
	{
		$$[0] = ((unsigned long)$1 << 16);
		$$[1] = 0;
	}
;

value_stmt: VALUE QUOTEDSTRING SEP QUOTEDSTRING '\n'
	{
		int len;
		int len2;

		expand_string($2, $2);
		len = strlen($2) + 1;
		expand_string($4, $4);
		len2 = strlen($4) + 1;
		
		$$ = (version_entry *)xmalloc(sizeof(version_entry) + (len + len2) * sizeof(wchar_t));
		$$->wValueLength = len2;
		$$->szKey = (wchar_t *)($$ + 1);
		ansi2uni($$->szKey, $2); 
		$$->wType = 1;
		$$->lpValue = $$->szKey + len;
		ansi2uni((wchar_t *)$$->lpValue, $4); 
		$$->entries = NULL;
	}
	| VALUE QUOTEDSTRING SEP NUMBER SEP NUMBER '\n'
	{
		int len;
		int len2 = 2 * sizeof(unsigned short);
		unsigned short * p;

		expand_string($2, $2);
		len = (strlen($2) + 1) * sizeof(wchar_t);
		
		$$ = (version_entry *)xmalloc(sizeof(version_entry) + len + len2);
		$$->wValueLength = len2;
		$$->szKey = (wchar_t *)($$ + 1);
		ansi2uni($$->szKey, $2); 
		$$->wType = 0;
		$$->lpValue = $$->szKey + strlen($2) + 1;
		p = (unsigned short *)$$->lpValue;
		p[0] = $4;
		p[1] = $6; 
		$$->entries = NULL;
	}
	| VALUE error '\n'
	{
		err_msg(GRC_err_invalid_versioninfo); 
		yyerrok; 
	}
;

block_entry: value_stmt
	{
		$$ = $1;
	}
	| block_stmt
	{
		$$ = $1;
	}
;

block_entries: block_entry 
	{
		$$ = list_new();
		list_add($$, (void *) $1);
	}
	| block_entries '\n'
	{
		$$ = $1;
	}
	| block_entries block_entry
	{
		$$ = $1;
		list_add($$, (void *) $2);
	}
;

block_stmt: BLOCK QUOTEDSTRING '\n' BEG '\n' block_entries END 
	{
		int len;

		expand_string($2, $2);
		len = (strlen($2) + 1) * sizeof(wchar_t);
		$$ = (version_entry *)xmalloc(sizeof(version_entry) + len);
		$$->wValueLength = 0;
		$$->szKey = (wchar_t *)($$ + 1);
		ansi2uni($$->szKey, $2);
		$$->wType = 1; 
		$$->lpValue = NULL;
		$$->entries = $6;
	}
	| BLOCK error END 
	{
		err_msg(GRC_err_invalid_versioninfo); 
		yyerrok; 
	}
;

block_stmts: block_stmt
	{
		$$ = list_new();
		list_add($$, (void *)$1);
	}
	|  block_stmts '\n'
	{
		$$ = $1;
	}
	| block_stmts block_stmt
	{
		$$ = $1;
		list_add($$, (void *)$2);
	}
;

rcdata: id_or_name RCDATA memflags '\n' default_options BEG '\n' rc_entries END
	{
		wchar_t type[2] = {INVAL_WCHAR, RT_RCDATA};

		getRcdata(type, $1, $3 | PURE | MOVEABLE, &$5, $8);
	}
	| id_or_name RCDATA '\n' default_options BEG '\n' rc_entries END
	{
		wchar_t type[2] = {INVAL_WCHAR, RT_RCDATA};

		getRcdata(type, $1, DISCARDABLE | PURE | MOVEABLE, &$4, $7);
	}
	| id_or_name RCDATA error END
	{ 
		err_msg(GRC_err_invalid_rcdata); 
		yyerrok; 
	}
;


rc_entry: NUMBER
	{
		int n;

		n = $1;
		$$ = new_rc_entry((void *)&n, 4);
	}
	| QUOTEDSTRING
	{
		int n;

		n = expand_string($1, $1);
		$$ = new_rc_entry($1, n);
	}
/*	| 'L' QUOTEDSTRING 
	{
		err_msg(GRC_err_invalid_rcdata);
	} */
;
 
rc_entries: rc_entry
	{
		$$ = list_new();
		list_add($$, (void *)$1);		
	}
	| rc_entries '\n'
	{
		$$ = $1;
	}
	| rc_entries SEP rc_entry '\n'
	{
		$$ = $1;
		list_add($$, (void *)$3);
	}
	| rc_entries error '\n'
	{
		err_msg(GRC_err_invalid_rcdata);
		yyerrok;
	}
;

toolbarres: id_or_name TOOLBAR memflags NUMBER ',' NUMBER '\n' default_options BEG '\n' toolbar_entries END
	{
		wchar_t type[2] = {INVAL_WCHAR, RT_TOOLBAR};

		getToolbar(type, $1, $3 | PURE | MOVEABLE, &$8, $4, $6, $11);

	}
	| id_or_name TOOLBAR NUMBER ',' NUMBER '\n' default_options BEG '\n' toolbar_entries END
	{
		wchar_t type[2] = {INVAL_WCHAR, RT_TOOLBAR};

		getToolbar(type, $1, DISCARDABLE | PURE | MOVEABLE, &$7, $3, $5, $10);
	}
;

toolbar_entries: /* empty */
	{
		$$ = list_new();
	}
	|toolbar_entries '\n'
	{
		$$ = $1;
	}
	|toolbar_entries SEPARATOR
	{
		short n;
		rcdata_entry *entry;

		$$ = $1;
		n = 0;
		entry = new_rc_entry(&n, 2);
		list_add($$, (void *)entry);
	}
	|toolbar_entries BUTTON NUMBER
	{
		short n;
		rcdata_entry *entry;

		$$ = $1;
		n = $3;
		entry = new_rc_entry(&n, 2);
		list_add($$, (void *)entry);
	}
;

dlginclude: id_or_name DLGINCLUDE QUOTEDSTRING '\n'
	{
		wchar_t type[2] = {INVAL_WCHAR, RT_DLGINCLUDE};
		node *list = list_new();
		rcdata_entry *entry;
		int len;

		len = expand_string($3, $3);
		$3[len + 1] = '\0';
		entry = new_rc_entry($3, len + 2);
		list_add(list, (void *)entry);		
		getRcdata(type, $1, DISCARDABLE | PURE | MOVEABLE, &globalTail, list);
	}
	| id_or_name DLGINCLUDE error END
	{ 
		err_msg(GRC_err_invalid_rcdata); 
		yyerrok; 
	}
;

userres: id_or_name id_or_name memflags '\n' default_options BEG '\n' rc_entries END
	{
		getRcdata($2, $1, $3 | PURE | MOVEABLE, &$5, $8);
	}
	| id_or_name id_or_name '\n' default_options BEG '\n' rc_entries END
	{
		getRcdata($2, $1, DISCARDABLE | PURE | MOVEABLE, &$4, $7);
	}
	| id_or_name id_or_name memflags file_name
	{
		getUserRC($2, $1, $3 | PURE | MOVEABLE, &globalTail, $4);
	}
	| id_or_name id_or_name file_name
	{
		getUserRC($2, $1, DISCARDABLE | PURE | MOVEABLE, &globalTail, $3);
	}
	| id_or_name id_or_name error '\n'
	{ 
		/* This was "found" too often in header files */
		if (!is_header(currentFile))
			err_msg(GRC_err_invalid_userres); 
		yyerrok; 
	}
;

%%

int
yyerror(char *s)
{
	/* don't print all error messages */
	/* avoid error information while compiling header files (i.e. Win32 BITMAP structure) */
	if(stricmp(s, "parse error") && !is_header(currentFile))
		fprintf(stderr, "%s:%d: %s\n", currentFile, lines-1, s);

	return 0;
}

void
getFileInfo(char *filename, int line)
{
	verbose(("compiling file: %s, start at line: %d\n", filename, line));
	strcpy(currentFile, filename);
	lines = line;
}

struct_control *
CONTROLWITHTITLE(char *name, int id, int x, int y, int cx, int cy,
                       int type, unsigned long style, unsigned long exstyle)
{
	struct_control *control = (struct_control *) xmalloc(sizeof(struct_control));
	DLGITEMTEMPLATE *ctrl = &control->control; 

	control->typeID[0] = INVAL_WCHAR; 
	control->typeID[1] = type; 
	if (name)
	{
		expand_string(name, name);
		ansi2uni(control->nameID, name); 
	}
	else
	{
		control->nameID[0] = '\0';
	}
	ctrl->id = id; 
	ctrl->x = x; 
	ctrl->y = y; 
	ctrl->cx = cx; 
	ctrl->cy = cy; 
	ctrl->style = style ; 
	ctrl->dwExtendedStyle = exstyle;
	return control;
}

struct_control *
CONTROLWITHTYPE(char *name, int id, int x, int y, int cx, int cy,
                char *type, unsigned long style, unsigned long exstyle)
{
	struct_control *control = (struct_control *) xmalloc(sizeof(struct_control));
	DLGITEMTEMPLATE *ctrl = &control->control; 

	ansi2uni(control->typeID, type); 
	if (name)
	{
		expand_string(name, name);
		ansi2uni(control->nameID, name); 
	}
	else
	{
		control->nameID[0] = '\0';
	}
	ctrl->id = id; 
	ctrl->x = x; 
	ctrl->y = y; 
	ctrl->cx = cx; 
	ctrl->cy = cy; 
	ctrl->style = style ; 
	ctrl->dwExtendedStyle = exstyle;
	return control;
}

struct_control *
CONTROLWITHID(int name, int id, int x, int y, int cx, int cy,
                       int type, unsigned long style, unsigned long exstyle)
{
	struct_control *control = (struct_control *) xmalloc(sizeof(struct_control));
	DLGITEMTEMPLATE *ctrl = &control->control; 

	control->typeID[0] = INVAL_WCHAR; 
	control->typeID[1] = type; 
	control->nameID[0] = INVAL_WCHAR;
	control->nameID[1] = name;
	ctrl->id = id; 
	ctrl->x = x; 
	ctrl->y = y; 
	ctrl->cx = cx; 
	ctrl->cy = cy; 
	ctrl->style = style ; 
	ctrl->dwExtendedStyle = exstyle;
	return control;
}

int
known_type(char *type)
{
	/* Tests if the string is a known control type and returns the corresponding value
		Otherwise it returns 0 */

	if (!stricmp(type, "Button"))
		return CTL_BUTTON;
	if (!stricmp(type, "Combobox"))
		return CTL_COMBOBOX;
	if (!stricmp(type, "Static"))
		return CTL_STATIC;
	if (!stricmp(type, "Edit"))
		return CTL_EDIT;
	if (!stricmp(type, "Listbox"))
		return CTL_LISTBOX;
	if (!stricmp(type, "Scrollbar"))
		return CTL_SCROLLBAR;

	return 0;
}

rcdata_entry*
new_rc_entry(void *data, int size)
{
	rcdata_entry *entry;

	entry = (rcdata_entry *) xmalloc(sizeof(rcdata_entry) + size);
	entry->size = size;
	memcpy(entry->field, data, size);

	return entry;
}
