Release 980601

Sun May 31 13:40:13 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [if1632/signal.c]
	Added display of exception name.

	* [loader/task.c]
	Yet another attempt at fixing SwitchStackTo/SwitchStackBack.

	* [memory/selector.c] [relay32/builtin32.c] [tools/build.c]
	  [win32/kernel32.c]
	Generate an assembly stub for Win32 register functions to make
	their names available at link time.

	* [programs/*/Makefile.in]
	Added hacks to support old resource compiler.

Fri May 29 16:27:14 1998  Marcus Meissner <marcus@jet.franken.de>

	* [tools/testrun]
	Merge of my testscripts at home into one single perl program
	(tested with perl5). Works only on Linux due to 'ps' and 'ipcs'
	magic.

	* [controls/menu.c]
	Added some DefaultMenuItem stubs.

	* [debugger/stabs.c]
	Fixed stabs loading, now supports (int,int) typeinfo format used
	by gcc-2.8 and egcs-1. If it still crashes, please mail me.

	* [if1632/][relay32/]
	Added msvideo.dll (stubs only)
	Replaced some ptr by str for stringcases
	Added some new stubs (VxDCall, FindCloseNotif....)

	* [misc/network.c]
	Some argument fixes.

	* [misc/registry.c][misc/cpu.c]
	Registry initialization partially rewritten and enhanced.

	* [scheduler/*.c]
	Some additions so we don't do kill(0,SIGUSR1) (kill processgroup
	instead of targeted thread)
	Added SetThreadContext.

Thu May 28 23:59:59 1998  Bertho Stultiens <bertho@akhphd.au.dk>

	* [tools/wrc/*]
	New resource compiler version 1.0.0 (28-May-1998)

	* [Make.rules.in] [Makefile.in]
	Changed and added rc rules to point to tools/wrc/wrc.

	* [configure.in] [include/config.h.in]
	Added check for function 'stricmp'.

	* [include/resource.h]
	Commented out the old resource structure to catch references.
	It also includes wrc_rsc.h.

	* [include/wrc_rsc.h]
	New file. Definitions for the resources generated with wrc.

	* [include/windows.h]
	Added #ifdef RC_INVOKED to exclude stdarg.h.
	Added SS_NOTIFY flag.

	* [include/winnls.h]
	Added SUBLANG_* definitions and corrected some defaults.

	* [loader/libres.c]
	Changed the sysres load functions to support wrc generated
	resources.

	* [resource/sysres_*.rc]
	Added #include <windows.h>

	* [resource/sysres.c]
	Changed declarations to match wrc's output

	* [resource/Makefile.in]
	Changed rules to work with wrc.

	* [tools/makedep.c]
	Changed generation of .rc file dependencies to .s target.

Thu May 28 22:28:39 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [files/file.c][include/windows.c][relay32/kernel32.spec]
	Implemented GetFileAttributesEx32A/W.

	* [misc/imagelist.h][include/commctrl.h][relay32/comctl32.spec]
	Added ImageList_Read and ImageList_Write stubs.
	Added ImageList_AddIcon function.
	Added ImageList_LoadImage. It is the same as ImageList_LoadImage32A.

	* [controls/header.c]
	Fixed bitmap drawing bug.
	Added full bitmap support.

	* [include/commctrl.h]
	Added missing header macros.

	* [controls/toolbar.c][include/toolbar.h][include/commctrl.h]
	  [controls/commctrl.c] [relay32/comctl32.spec]
	First implementation of toolbar control.
	Implemented CreateToolbar, CreateToolbarEx and CreateMappedBitmap.

	* [controls/progress.c][controls/status.c]
	Some code cleanup.

	* [controls/commctrl.c][include/commctrl.h][relay32/comctl32.spec]
	Removed CreateStatusWindow16 and DrawStatusText16.
	CreateStatusWindow is the same as CreateStatusWindow32A.
	DrawStatusText is the same as DrawStatusText32A.

Thu May 28 16:01:28 1998  Matthew J. Francis  <asbel@dial.pipex.com>

	* [objects/bitmap.c] [objects/bitmap.h] [objects/oembitmap.c]
	  [objects/dc.c] [graphics/x11drv/bitblt.c]
	Added partial implementation of CreateDIBSection, with great thanks
	to Ulrich Weigand <weigand@informatik.uni-erlangen.de> for
	contributing the bulk of the patch.

Wed May 27 19:04:31 1998  Ulrich Weigand <weigand@informatik.uni-erlangen.de>

	* [win32/kernel32.c] [if1632/thunk.c] [include/flatthunk.h]
	ThunkConnect16 and related functions moved to emulator.

	* [loader/ne/segment.c]
	Call DllEntryPoint with correct arguments.

	* [relay32/builtin32.c]
	Bugfix: Relay debugging did not work for multiple processes.

	* [controls/menu.c]
	Bugfix: dwItemData was not set for MF_OWNERDRAW menus.

	* [if1632/relay.c] [relay32/relay386.c]
	Relay messages converted to use DPRINTF.

	* [controls/desktop.c] [relay32/user32.spec]
	Implemented PaintDesktop.

	* [files/profile.c] [if1632/kernel.spec] [misc/network.c]
	  [misc/printdrv.c] [relay32/winspool.spec] 
	  [win32/ordinals.c] [relay32/kernel32.spec]
	Some stubs added.

	* [relay32/mpr.spec]
	All ordinals were off by one.

Tue May 26 13:32:57 1998  Bill Hawes <whawes@star.net>

	* [misc/lstr.c] [include/casemap.h] [tools/unimap.pl]
	Added Unicode case conversion routines towupper/towlower,
	with mapping tables casemap.h created by tools/unimap.pl.

	* [misc/ntdll.c] [include/winnls.h] [relay32/ntdll.spec]
	  [relay32/advapi.spec]
	Minimal implementation of IsTextUnicode, just enough to get
	NT4 notepad to open ascii/unicode files.

	* [Make.rules.in] [resources/sysres_En.rc]
	Added include file dlgs.h for building resource files, so that
	resources can refer to defined values (e.g. pshHelp).

	* [misc/crtdll.c] [relay32/crtdll.spec]
	Use towupper/towlower for 32W case conversions.

	* [memory/string.c]
	Use towupper for 32W case conversions.

	* [ole/ole2nls.c]
	Use towupper for 32W case conversions; fix mem leak; minor cleanup

	* [controls/edit.c]
	Added soft break flag to edit state. Print unknown action values
	for WM_VSCROLL (action 190 occurs when running NT4 notepad.)

Mon May 25 22:42:40 1998  Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>

	* [files/file.c]
	Care for a pathological case in SetFilePointer.

	* [graphics/x11drv/xfont.c]
	Handle longer Font names in LFD_ComposeLFD and try to catch errors.

	* [loader/pe_image.c]
	Unload Dummymodule when PE_LoadLibraryEx32A fails with
	PE_LoadImage (makes Encarta 98 installer proceed).

	* [misc/registry.c]
	Move a check for a special case in RegCreateKeyEx32W after the
	check for existence.

Tue May 25 20:18:26 1998  Matthew Becker <mbecker@glasscity.net>

	* [misc/ntdll.c]
	Added some stubs, just guessing at the size of their param lists.

	* [misc/registry.c]
	Added stubs for RegUnLoadKey, RegSetKeySecurity, RegSaveKey,
	RegRestoreKey, and RegReplaceKey

	* [programs/regtest/regtest.c]
	Updated registry testing program.

Sun May 24 18:11:40 1998  Alex Priem <alexp@sci.kun.nl>

	* [file/profile.c]
	Added flag 'return_values' to PROFILE_GetSection.

Sun May 24 13:41:10 1998  James Juran <jrj120@psu.edu>

	* [misc/shell.c] [files/directory.c]
	Documentation/debugging info additions.

	* [*/*.c] [include/*.h]
	Moved many extern function definitions to appropriate header files.
	Cleaned up a few compile warnings.
	If #include "debug.h" is present, removed #include <stdio.h>.
	debug.h includes stdio.h, so it is not necessary to include both.

	* [graphics/*.c] [if1632/signal.c] [ipc/*.c] [scheduler/*.c]
	  [win32/*.c] [windows/*.c]
	Final patch to convert fprintf statements to new debugging interface.
	Some fprintfs are still left, especially in the debugger/ directory.
	However, IMHO, it's not worth the effort to change the rest.

Fri May 22 21:58:35 1998  Morten Welinder  <terra@diku.dk>

	* [windows/keyboard.c]
	Correct handling of keys "`-=[]\;',./".

Fri May 22 12:06:00 1998  Per Lindström <pelinstr@algonet.se>

	* [include/windows.h] [relay32/kernel32.spec] [win32/console.c]
	Added stub for ReadConsoleOutputCharacter32A.

Thu May 21 16:45:48 1998  Pascal Cuoq <pcuoq@ens-lyon.fr>

	* [ole/ole2nls.c]
	Began better implementation of LCMapString32A.
	Not very well tested yet, and still need improvements.

	* [controls/scroll.c]
	Documented functions.

Wed May 20 21:37:56 1998  Peter Hunnisett <hunnise@nortel.ca>

	* [include/windows.h][misc/main.c]
	Change SystemParameterInfo to support SPI_GETHIGHCONTRAST. Also
	include some missing SPI_ definitions.

	* [include/dsound.h][multimedia/dsound.c][relay32/dplayx.spec]
	Added stubs for DirectPlayLobbyCreate[AW]. Not sure if these
	should go into a new files dplayx.c? Anyone care?

	* [include/winnls.h]
	Added two missing flags for the CompareString32 functions.
diff --git a/tools/build.c b/tools/build.c
index 319b6e7..bc36294 100644
--- a/tools/build.c
+++ b/tools/build.c
@@ -971,7 +971,7 @@
 static int BuildSpec32File( char * specfile, FILE *outfile )
 {
     ORDDEF *odp;
-    int i, nb_names, nb_reg_funcs = 0;
+    int i, nb_names;
 
     fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n\n",
              specfile );
@@ -988,6 +988,25 @@
                  i, DLLName, i );
     }
 
+    /* Output code for all register functions */
+
+    fprintf( outfile, "#ifdef __i386__\n" );
+    for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
+    {
+        if (odp->type != TYPE_REGISTER) continue;
+        fprintf( outfile,
+                 "__asm__(\".align 4\\n\\t\"\n"
+                 "        \".globl " PREFIX "%s\\n\\t\"\n"
+                 "        \".type " PREFIX "%s,@function\\n\\t\"\n"
+                 "        \"%s:\\n\\t\"\n"
+                 "        \"pushl $" PREFIX "__regs_%s\\n\\t\"\n"
+                 "        \"pushl $" PREFIX "CALL32_Regs\\n\\t\"\n"
+                 "        \"ret\");\n",
+                 odp->u.func.link_name, odp->u.func.link_name,
+                 odp->u.func.link_name, odp->u.func.link_name );
+    }
+    fprintf( outfile, "#endif\n" );
+
     /* Output the DLL functions prototypes */
 
     for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
@@ -1106,7 +1125,6 @@
             break;
         case TYPE_REGISTER:
             args = 0xfe;
-            nb_reg_funcs++;
             break;
         default:
             args = 0xff;
@@ -1125,7 +1143,6 @@
     fprintf( outfile, "    %d,\n", Base );
     fprintf( outfile, "    %d,\n", Limit - Base + 1 );
     fprintf( outfile, "    %d,\n", nb_names );
-    fprintf( outfile, "    %d,\n", nb_reg_funcs );
     fprintf( outfile,
              "    Functions,\n"
              "    FuncNames,\n"
diff --git a/tools/makedep.c b/tools/makedep.c
index 11f77d3..c45eb0c 100644
--- a/tools/makedep.c
+++ b/tools/makedep.c
@@ -279,7 +279,7 @@
         else if (!strcmp( ext, ".rc" ))  /* resource file */
         {
             *ext = '\0';
-            fprintf( file, "%s.c %s.h: %s", obj, obj, pFile->filename );
+            fprintf( file, "%s.s: %s", obj, pFile->filename );
             *column += 2 * strlen(obj) + strlen(pFile->filename) + 7;
         }
         else
diff --git a/tools/testrun b/tools/testrun
new file mode 100755
index 0000000..499e134
--- /dev/null
+++ b/tools/testrun
@@ -0,0 +1,274 @@
+#!/usr/bin/perl
+# Copyright 1996-1998 Marcus Meissner
+# IPC remove code Copyright 1995 Michael Veksler
+#
+# This perl script automatically test runs ALL windows .exe and .scr binaries
+# it finds (and can access) on your computer. It creates a subdirectory called
+# runs/ and stores the output there. It also does (unique) diffs between runs.
+#
+# It only reruns the test if ChangeLog or the executeable is NEWER than the
+# run file. (If you want to rerun everything inbetween releases, touch
+# ChangeLog.)
+
+#
+# BEGIN OF USER CONFIGURATION
+#
+# Path to WINE executeable. If not specified, 'wine' is searched in the path.
+#
+$wine = 'wine';
+#
+# WINE options. -managed when using a windowmanager is probably not good in
+# automatic testruns.
+#
+$wineoptions='';
+#
+# Path to WINE ChangeLog. Used as timestamp for new releases...
+#
+$changelog = '/home/marcus/wine/ChangeLog';
+# 
+# How long before automatically killing all subprocesses
+# 30 is good for automatic testing, 300 or more for interactive testing.
+#
+$waittime = 30;
+#
+#diff command
+#
+$diff='diff -u';
+#
+# truncate at how-much-lines
+#
+$trunclines=200;
+#
+$<||die "Running this script under UID 0 is a great security risk (and risk for existing windows installations on mounted DOS/W95 partitions). If you really want to, comment out this line.\n";
+#
+# END OF USER CONFIGURATION
+#
+
+if (! -d "runs") { die "no subdirectory runs/ found in $cwd. Please create one first!\n";}
+
+# look for the exact path to wine executeable in case we need it for a 
+# replacement changelog.
+if (! ($wine =~ /\//)) { # no path specified. Look it up.
+	@paths = split(/:/,$ENV{'PATH'});
+	foreach $path (@paths) {
+		if (-e "$path/$wine" && -x "$path/$wine") {
+			$wine = "$path/$wine";
+			last;
+		}
+	}
+}
+
+# if we don't have a changelog use the modification date of the WINE executeable
+if (! -e $changelog) {
+	$changelog = $wine;
+}
+
+# sanity check so we just fill runs/ with errors.
+(-x $wine)  || die "no $wine executable found!\n";
+# dito. will print usage
+system("$wine -h >/dev/null")||die "wine call failed:$!\n";
+
+print "Using $wine as WINE executeable.\n";
+print "Using $changelog as testrun timereference.\n";
+
+chomp($cwd = `pwd`);
+
+# Find out all present semaphores so we don't remove them later.
+$IPC_RMID=0;
+$USER=$ENV{'USER'};
+open(IPCS,"ipcs|");
+while(<IPCS>) {
+    split;
+    # try to find out the IPC-ID, assume it is the first number.
+    foreach (@_) {
+	$_ ne int($_) && next;	# not a decimal number
+	$num=$_;
+	last;
+    }
+    if (/sem/i .. /^\s*$/ ) {
+	index($_,$USER)>=0 || next;
+	$sem_used{$num}=1;
+	print "found $num\n";
+    }
+}
+close(IPCS);
+
+sub kill_subprocesses {
+	local($killedalready,%parentof,%kids,$changed,%cmdline);
+
+	# FIXME: Linux ps dependend...
+	#
+	open(PSAUX,"ps --format pid,ppid,comm|");
+	# lookup all processes, remember their parents and cmdlines.
+	%parentof=();
+	while (<PSAUX>) {
+		if (/\s*(\d*)\s*(\d*)\s*(\S*)/) {
+			$parentof{$1}=$2;
+			$cmdline{$1}=$3;
+		}
+	}
+	close(PSAUX);
+
+	# find out all kids of this perlscript
+	%kids = ();
+	$kids{$$} = 1;
+	$changed = 1;
+	while ($changed) {
+		$changed = 0;
+		foreach (keys %parentof) {
+			next if ($kids{$_});
+			if ($kids{$parentof{$_}}) {
+				$changed = 1;
+				$kids{$_}=1;
+			}
+		}
+	}
+	# .. but do not consider us for killing
+	delete $kids{$$};
+	# remove all processes killed in the meantime from %killedalready.
+	foreach $pid (keys %killedalready) {
+		delete $killedalready{$pid} if (!$kids{$pid} );
+	}
+	# kill all subprocesses called 'wine'. Do not kill find, diff, sh
+	# and friends, which are also subprocesses of us.
+	foreach (keys %kids) {
+		next unless ($cmdline{$_} =~ /wine/);
+		# if we have already killed it using -TERM, use -KILL
+		if ($killedalready{$_}) {
+			kill(9,$_);	# FIXME: use correct number?
+		} else {
+			kill(15,$_);	# FIXME: use correct number?
+		}
+		$killedalready{$_}=1;
+	}
+	alarm($waittime);		# wait again...
+};
+
+# borrowed from tools/ipcl. See comments there.
+# killing wine subprocesses unluckily leaves all of their IPC stuff lying
+# around. We have to wipe it or we run out of it.
+sub cleanup_wine_ipc {
+	open(IPCS,"ipcs|");
+	while(<IPCS>) {
+	    split;
+	    # try to find out the IPC-ID, assume it is the first number.
+	    foreach (@_) {
+		$_ ne int($_) && next;	# not a decimal number
+		$num=$_;
+		last;
+	    }
+	    # was there before start of this script, skip it.
+	    #
+	    # FIXME: this doesn't work for programs started during the testrun.
+	    #
+	    if (/sem/i .. /^\s*$/ ) {
+		index($_,$USER)>=0 || next;
+		push(@sem,$num);
+	    }
+	}
+	foreach (@sem) {
+	    $sem_used{$_} && next;
+	    semctl($_, 0, $IPC_RMID,0);
+	}
+	close(IPCS);
+}
+
+# kill all subwineprocesses for automatic runs.
+sub alarmhandler {
+	print "timer triggered.\n";
+	&kill_subprocesses;
+}
+
+$SIG{'ALRM'} = "alarmhandler";
+
+# NOTE: following find will also cross NFS mounts, so be sure to have nothing
+# mounted that's not on campus or add relevant ! -fstype nfs or similar.
+#
+
+open(FIND,"find / -type f  \\( -name \"*.EXE\" -o -name \"*.exe\" -o -name \"*.scr\" -o -name \"*.SCR\" \\) -print|");
+while ($exe=<FIND>) {
+	chop($exe);
+
+	# This could change during a testrun (by doing 'make' for instance)
+	# FIXME: doesn't handle missing libwine.so during compile...
+	(-x $wine)  || die "no $wine executable found!\n";
+
+	# Skip all mssetup, acmsetup , installshield whatever exes. 
+	# they seem to work, mostly and starting them is just annoying.
+	next if ($exe =~ /acmsetup/);
+	next if ($exe =~ /unwise/);
+	next if ($exe =~ /testexit/);
+	next if ($exe =~ /_msset/);
+	next if ($exe =~ /isun/i);
+	next if ($exe =~ /st4u/);
+	next if ($exe =~ /st5u/);
+	next if ($exe =~ /_mstest/);
+	next if ($exe =~ /_isdel/);
+	next if ($exe =~ /ms-setup/);
+	next if ($exe =~ /~mss/);
+	next if ($exe =~ /unin/);
+
+	$runfile = $exe;
+	$runfile =~ s/[\/ ]/_/g;
+	$runfile =~ s/\.exe$//g;
+	$runfile =~ s/\.scr$//ig;
+	$flag=0;
+	#
+	# Check if changelog is newer, if not, continue
+	#
+	if (	-e "runs/${runfile}.out" && 
+		(-M $changelog > -M "runs/${runfile}.out") && 
+		(-M $exe > -M "runs/${runfile}.out")
+	) {
+		#print "skipping $exe, already done.\n";
+		next;
+	}
+
+	# check runfile if the exe is a DOS executeable or 
+	# of different architecture (win32)
+	if (open(RUNFILE,"runs/$runfile.out")) {
+		while ($xrun=<RUNFILE>) {
+			chop($xrun);
+			if ($xrun=~ /LoadModule:.*error=11$/) {
+				$flag=1;
+				last;
+			}
+			if ($xrun=~ /LoadModule:.*error=21$/) {
+				$flag=2;
+				last;
+			}
+		}
+		close(RUNFILE);
+		if ($flag==1) {
+			#print "skipping $exe, seems to be a DOS executable.\n";
+			next;
+		}
+		if ($flag==2) {
+			#print "skipping $exe, seems to be a non i386 executable.\n";
+			next;
+		}
+	}
+	# now testrun...
+	print "$exe:\n";
+	$dir = $exe;
+	$dir =~ s/^(.*)\/[^\/]*$/$1/; #cut of the basename.
+
+	alarm($waittime);
+
+	chdir($dir)||die "$dir:$!";
+	if ($exe =~ /\.scr/i) {
+		system("echo quit|$wine $wineoptions \"$exe /s\" >$cwd/${runfile}.out 2>&1");
+	} else {
+		system("echo quit|$wine $wineoptions \"$exe\" >$cwd/${runfile}.out 2>&1");
+	}
+	alarm(1000);# so it doesn't trigger in the diff, kill or find.
+
+	system("touch $cwd/runs/${runfile}.out");
+	system("$diff $cwd/runs/${runfile}.out $cwd/${runfile}.out");
+	system("head -$trunclines $cwd/${runfile}.out >$cwd/runs/${runfile}.out");
+	unlink("$cwd/${runfile}.out");
+	&kill_subprocesses;
+	&cleanup_wine_ipc;
+	chdir($cwd);
+}
+close(FIND);
diff --git a/tools/unimap.pl b/tools/unimap.pl
new file mode 100644
index 0000000..0b3282f
--- /dev/null
+++ b/tools/unimap.pl
@@ -0,0 +1,121 @@
+#!/usr/bin/perl
+#
+# Reads the Unicode 2.0 "unidata2.txt" file and selects encodings
+# for case pairs, then builds an include file "casemap.h" for the
+# case conversion routines. 
+
+use integer
+
+$INFILE	= "unidata2.txt";
+$OUT	= ">casemap.h";
+$TEST	= ">allcodes";
+
+# Open the data file ...
+open INFILE	or die "Can't open input file $INFILE!\n";
+open OUT	or die "Can't open output file $OUT!\n";
+open TEST	or die "Can't open output file $OUT!\n";
+
+#Initialize the upper and lower hashes
+%lwrtable = ();
+%uprtable = ();
+@low = ("0") x 256;
+@upr = ("0") x 256;
+
+while ($line = <INFILE> )
+{
+	# Decode the fields ...
+	($code, $name, $cat, $comb, $bidi, 
+	 $decomp, $dec, $dig, $num, $mirror, 
+	 $oldname, $comment, $upper, $lower, $title) = split /;/, $line;
+
+	#Get the high byte of the code
+	$high = substr $code, 0, 2;
+	if ($lower ne "") {
+		$low[hex $high] = "lblk" . $high;
+		$lwrtable{$code} = $lower;
+	}
+	if ($upper ne "") {
+		$upr[hex $high] = "ublk" . $high;
+		$uprtable{$code} = $upper;
+	}
+	#Write everything to the test file
+	printf TEST "%s %s %s\n", $code, 
+		$upper ne "" ? $upper : "0000",
+		$lower ne "" ? $lower : "0000";
+
+}
+close(FILE);
+close TEST;
+
+#Generate the header file
+print OUT "/*\n";
+print OUT " * Automatically generated file -- do not edit!\n";
+print OUT " * (Use tools/unimap.pl for generation)\n";
+print OUT " *\n";
+print OUT " * Mapping tables for Unicode case conversion\n";
+print OUT " */\n\n";
+
+#Write out the non-trivial mappings
+for ($high = 0; $high < 256; $high++) {
+	#Check whether the table is needed
+	if (length $low[$high] < 6) {
+		next;
+	}
+	printf OUT "/* Lowercase mappings %02X00 - %02XFF */\n",
+		$high, $high;
+	printf OUT "static const WCHAR lblk%02X[256] = {\n", $high;
+	for ($low = 0; $low < 256; $low += 8) {
+		@patch = ();
+		for ($i = 0; $i < 8; $i++) {
+			$code = sprintf "%02X%02X", $high, $low + $i;
+			$map = $lwrtable{$code};
+			if ($map eq "") {
+				$map = $code;
+			}
+			$patch[$i] = "0x" . $map;
+		}
+		printf OUT "\t%s, %s, %s, %s, %s, %s, %s, %s,\n",
+			@patch;
+	}
+	print OUT "};\n\n";
+}
+print OUT "static const WCHAR * const lwrtable[256] = {\n";
+for ($i = 0; $i < 256; $i += 8) {
+	@patch = @low[$i+0 .. $i+7];
+	printf OUT "\t%06s, %06s, %06s, %06s, %06s, %06s, %06s, %06s,\n",
+		@patch;
+}
+print OUT "};\n\n";
+
+for ($high = 0; $high < 256; $high++) {
+	#Check whether the table is needed
+	if (length $upr[$high] < 6) {
+		next;
+	}
+	printf OUT "/* Uppercase mappings %02X00 - %02XFF */\n",
+		$high, $high;
+	printf OUT "static const WCHAR ublk%02X[256] = {\n", $high;
+	for ($low = 0; $low < 256; $low += 8) {
+		@patch = ();
+		for ($i = 0; $i < 8; $i++) {
+			$code = sprintf "%02X%02X", $high, $low + $i;
+			$map = $uprtable{$code};
+			if ($map eq "") {
+				$map = $code;
+			}
+			$patch[$i] = "0x" . $map;
+		}
+		printf OUT "\t%s, %s, %s, %s, %s, %s, %s, %s,\n",
+			@patch;
+	}
+	print OUT "};\n\n";
+}
+print OUT "static const WCHAR * const uprtable[256] = {\n";
+for ($i = 0; $i < 256; $i += 8) {
+	@patch = @upr[$i+0 .. $i+7];
+	printf OUT "\t%06s, %06s, %06s, %06s, %06s, %06s, %06s, %06s,\n",
+		@patch;
+}
+print OUT "};\n\n";
+
+close(OUT);
diff --git a/tools/wrc/Makefile.in b/tools/wrc/Makefile.in
new file mode 100644
index 0000000..85eae63
--- /dev/null
+++ b/tools/wrc/Makefile.in
@@ -0,0 +1,41 @@
+DEFS      = -D__WINE__
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+
+PROGRAMS = wrc@PROGEXT@
+MODULE   = none
+
+C_SRCS = \
+	dumpres.c \
+	genres.c \
+	newstruc.c \
+	preproc.c \
+	readres.c \
+	utils.c \
+	wrc.c \
+	writeres.c
+
+EXTRA_SRCS = parser.y parser.l
+EXTRA_OBJS = y.tab.o lex.yy.o
+
+all: $(PROGRAMS)
+
+depend:: y.tab.h
+
+@MAKE_RULES@
+
+wrc@PROGEXT@: $(OBJS)
+	$(CC) $(CFLAGS) -o wrc@PROGEXT@ $(OBJS) $(LEXLIB)
+
+y.tab.c y.tab.h: parser.y
+	$(YACC) -d -t $(SRCDIR)/parser.y
+
+lex.yy.c: parser.l
+	$(LEX) -8 $(SRCDIR)/parser.l
+
+clean::
+	$(RM) y.tab.c y.tab.h lex.yy.c
+
+### Dependencies:
diff --git a/tools/wrc/README.wrc b/tools/wrc/README.wrc
new file mode 100644
index 0000000..7c2b47a
--- /dev/null
+++ b/tools/wrc/README.wrc
@@ -0,0 +1,258 @@
+This is the first release (1.0.0 (28-May-1998)) of the new resource compiler
+'wrc'. It improves the winerc implementation by these features:
+
+- source preprocessing
+- 16 and 32 bit support
+- LANGUAGE support (32 bit only)
+- almost all resource types are supported
+- enhanced expression capabilities and resource naming
+- indirect loadable resources
+- NE/PE resource directory generation
+- binary .res file generation/reading
+
+Wrc generates an assembly file that can be assembled with GNU's gas, or
+passed to gcc. The assembly became necessary for two reasons. First, C does
+not ensure relative position of declared data. Secondly, C complaints about
+complex initialization schemes that became necessary with the NE/PE
+directory generation.
+
+
+Wrc command-line
+----------------
+You can get this message by typing 'wrc -?':
+
+Usage: wrc [options...] [infile[.rc|.res]]
+   -a n        Alignment of resource (win16 only, default is 4)
+   -b          Create a C array from a binary .res file
+   -c          Add 'const' prefix to C constants
+   -C cp       Set the resource's codepage to cp (default is 0)
+   -d n        Set debug level to 'n'
+   -D id[=val] Define preprocessor identifier id=val
+   -e          Disable recognition of win32 keywords in 16bit compile
+   -g          Add symbols to the global c namespace
+   -h          Also generate a .h file
+   -H file     Same as -h but written to file
+   -I path     Set include search dir to path (multiple -I allowed)
+   -l lan      Set default language to lan (default is neutral {0})
+   -n          Do not generate .s file
+   -o file     Output to file (default is infile.[res|s|h]
+   -p prefix   Give a prefix for the generated names
+   -r          Create binary .res file (compile only)
+   -s          Add structure with win32/16 (PE/NE) resource directory
+   -t          Generate indirect loadable resource tables
+   -T          Generate only indirect loadable resources tables
+   -V          Print version end exit
+   -w 16|32    Select win16 or win32 output (default is win32)
+   -W          Enable pedantic warnings
+
+Input is taken from stdin if no sourcefile specified.
+
+Debug level 'n' is a bitmask with following meaning:
+    * 0x01 Tell which resource is parsed (verbose mode)
+    * 0x02 Dump internal structures
+    * 0x04 Create a parser trace (yydebug=1)
+
+The -o option only applies to the final destination file, which is
+in case of normal compile a .s file. You must use the '-H header.h'
+option to override the header-filename.
+If no input filename is given and the output name is not overridden
+with -o and/or -H, then the output is written to "wrc.tab.[sh]"
+
+
+Preprocessing
+-------------
+The build-in preprocessor is not a full implementation of the C counterpart.
+Wrc does not understand function-type macros. These are discarded as they
+are scanned. This will be a future project. Wrc does understand these:
+#define
+#if
+#ifdef
+#ifndef
+#elif
+#else
+#endif
+#error
+
+Also 'defined' is supported as operator (both with and without parenthesis).
+'#if' expressions can be anything valid that evaluates to an integer
+expression (where 0 is false and anything else is true). Others (#pragma,
+#line) are ignored. A special case '#' generates an error. This is due to
+the implementation to enable generation of errors on preprocessing and will
+be improved in the future.
+
+
+16 and 32 bit support
+---------------------
+All of wrc is layed out in such a way that it enables compilation of both 16
+and 32 bit resources. They mainly differ in code-generation and extra
+keywords. Win32 keywords are recognized by default in 16 bit compile. You
+can disable recognition of win32 reserved keywords by using the '-e' option,
+if you encounter .rc-files that use win32 reserved keywords (I strongly
+recommend that you just rename things in the source).
+
+
+Language support
+----------------
+Wrc also understands the LANGUAGE keyword (win32 only) for both global and
+local definitions of language. There are differences with respect to MS' and
+Borland's implementation. Wrc uses 0,0 as the default language if non is
+specified. Both MS and Borland use the language of the system that the
+compiler runs on.
+
+Not all resource-types can have local language keywords attached yet
+(notably: BITMAP, CURSOR, ICON and usertype). This is due to implementation
+of filename-scanning and the complexity that it poses. This will be changed
+in the next release.
+
+
+Resource types supported
+------------------------
+All types are supported except for:
+- FONT
+- MESSAGETABLE
+- extensions like TOOLBAR and the like
+
+These types will be implemented as soon as I get a proper specification of
+the layout.
+
+Note: Usertype resources with character strings as types have a different
+layout and do not accept expressions when a numerical type is specified. The
+must be enclosed in double quotes. These are examples of valid usertype
+resources:
+
+MyName "MyType" mydata.bin
+MyName 12345 mydata.bin
+MyName "MyType" "mydata.bin"
+MyName 12345 "mydata.bin"
+
+MyName "MyType"
+{
+  ..., data, ...
+}
+
+or
+
+MyName 12345
+{
+ ..., data, ...
+}
+
+
+Expression capabilities and resource names
+------------------------------------------
+You can use an expression in most places where the resource definition
+expects a number (except usertype type). Operators supported: 
+()	parenthesis
+*	multiply
+/	divide
++	add
+-	minus/substract
+|	binary or
+&	binary and
+~	binary not (unary operator though)
+NOT	... (sigh)
+
+Minus (-) can both be unary and binary. The NOT operator is (primarily)
+used to disable window styles but I strongly suggest to refrain from using
+this operator.
+There is a shift/reduce conflict on the unary minus, but this is not
+problematic. I was too lazy to make a new expression parser (next version or
+so). Unary plus (+) would cause another confilct, so I let it out for now.
+
+Resource names can be both numerical (expressions) and character typed. Wrc
+does supports this insane (deep sigh) construct:
+
+MENU MENU
+{
+ ...
+}
+
+It is _ONLY_ supported for backwards compatibility so that old sources can
+be compiled with winelib. DO NOT USE IT IN NEW RESOURCES, PLEASE!
+
+
+Indirect loadable resources
+---------------------------
+
+Wrc can generate tables for indirect resource loading like winerc did. There
+are two new structures defined in 'wine-base-dir/include/wrc_rsc.h':
+
+typedef struct wrc_resource16
+{
+        INT32   resid;          /* The resource id if resname == NULL */
+        LPSTR   resname;
+        INT32   restype;        /* The resource type-id if typename == NULL */
+        LPSTR   typename;
+        LPBYTE  data;           /* Actual resource data */
+        UINT32  datasize;       /* The size of the resource */
+} wrc_resource16_t;
+
+typedef struct wrc_resource32
+{
+        INT32   resid;          /* The resource id if resname == NULL */
+        LPWSTR  resname;
+        INT32   restype;        /* The resource type-id if typename == NULL */
+        LPWSTR  typename;
+        LPBYTE  data;           /* Actual resource data */
+        UINT32  datasize;       /* The size of the resource */
+} wrc_resource32_t;
+
+The extension to winerc lies in the addition of the 'typename' field to
+support usertype resoursec with names for types.
+
+Note that _ALL_ names generated by wrc and to be used in interfacing with
+wine are PASCAL-style strings, unlike winerc. The first element contains the
+length and the strings are _not_ '\0'-terminated!
+
+You can also generate header files with wrc when specifying the '-h' or
+'-H<filename>' option.
+
+
+NE/PE resource directory generation
+-----------------------------------
+A windows executable has a table/directory of resources avalable in that
+module. Wrc will generate this directory with the '-s' option and place it
+in the assembly output (and header-file). This will enable the separation
+of different modules (dlls) in wine, which is the next project after wrc.
+
+The layout of the PE directory should be exactly like the executable file.
+The NE-directory layout _DIFFERS_ from the real NE-executable in such way
+that all offsets to actual resource-data is relative to the NE-directory and
+_NOT_ the beginning of the file.
+
+
+Binary .res file generation/reading
+-----------------------------------
+Wrc can both generate (32 and 16 bit) and read (32 bit only) .res-files.
+These can be used as intermediate files or binary files can be imported from
+other sources. The reading of 16 bit .res-files is on the list for the next
+release.
+
+You cannot convert 32 bit .res-files into 16 bit output or vice versa. I
+might implement 16 bit res into 32 bit output in the future, but I stronly
+oppose to the other way arround.
+
+
+Bugs
+----
+Inherent to programs you have bugs. These I know are there, plus a few
+things that I noted in the above text (more lack of implementation than bug
+though):
+- No codepage translation
+- UNICODE translations are not/not correct implemented
+- No documentation ('wrc -?' gives command-line options though)
+- grep for FIXME in the source
+
+
+Reporting bugs and patches
+--------------------------
+Send problems to the wine newsgroup or, preferrably,  directly to me at:
+
+bertho@akhphd.au.dk
+
+Please send the problematic rc-source with the bug so I can reproduce it.
+Patches should _not_ be send to Alexandre but to me. I will then review the
+change and send a full patch to be included into the new wine release (I
+prefer 'diff -u' format). You can always upload suggestions to wine
+headquarters, but be sure to send me a copy.
+
diff --git a/tools/wrc/dumpres.c b/tools/wrc/dumpres.c
new file mode 100644
index 0000000..33c09f4
--- /dev/null
+++ b/tools/wrc/dumpres.c
@@ -0,0 +1,907 @@
+/*
+ * Copyrignt 1998 Bertho A. Stultiens (BS)
+ *
+ * 16-Apr-1998 BS	- Yeah, dump it to stdout.
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <config.h>
+#include "wrc.h"
+#include "dumpres.h"
+
+/*
+ *****************************************************************************
+ * Function	: get_typename
+ * Syntax	: char *get_typename(resource_t* r)
+ * Input	:
+ *	r	- Resource description
+ * Output	: A pointer to a string representing the resource type
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+char *get_typename(resource_t* r)
+{
+	switch(r->type){
+	case res_acc:	return "ACCELERATOR";
+	case res_bmp:	return "BITMAP";
+	case res_cur:	return "CURSOR";
+	case res_curg:	return "GROUP_CURSOR";
+	case res_dlg:	return "DIALOG";
+	case res_dlgex:	return "DIALOGEX";
+	case res_fnt:	return "FONT";
+	case res_ico:	return "ICON";
+	case res_icog:	return "GROUP_ICON";
+	case res_men:	return "MENU";
+	case res_menex:	return "MENUEX";
+	case res_rdt:	return "RCDATA";
+	case res_stt:	return "STRINGTABLE";
+	case res_usr:   return "UserResource";
+	case res_msg:	return "MESSAGETABLE";
+	case res_ver:	return "VERSIONINFO";
+	default: 	return "Unknown";
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: strncpyWtoA
+ * Syntax	: char *strncpyWtoA(char *cs, short *ws, int maxlen)
+ * Input	:
+ *	cs	- Pointer to buffer to receive result
+ *	ws	- Source wide-string
+ *	maxlen	- Max chars to copy
+ * Output	: 'cs'
+ * Description	: Copy a unicode string to ascii. Copying stops after the
+ *		  first occuring '\0' or when maxlen-1 chars are copied. The
+ *		  String is always nul terminated.
+ * Remarks	: No codepage translation is done.
+ *****************************************************************************
+*/
+char *strncpyWtoA(char *cs, short *ws, int maxlen)
+{
+	char *cptr = cs;
+	while(*ws && maxlen-1)
+	{
+		if(*ws < -128 || *ws > 127)
+			printf("***Warning: Unicode string contains non-printable chars***");
+		*cptr++ = (char)*ws++;
+		maxlen--;
+	}
+	*cptr = '\0';
+	return cs;
+}
+
+/*
+ *****************************************************************************
+ * Function	: print_string
+ * Syntax	: void print_string(string_t *str)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void print_string(string_t *str)
+{
+	char buffer[512];
+	if(!str)
+		printf("<none>");
+	else if(str->type == str_char)
+		printf("\"%s\"", str->str.cstr);
+	else
+	{
+		strncpyWtoA(buffer, str->str.wstr, sizeof(buffer));
+		printf("L\"%s\"", buffer);
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: get_nameid_str
+ * Syntax	: char *get_nameid_str(name_id_t *n)
+ * Input	:
+ *	n	- nameid to convert to text
+ * Output	: A pointer to the name.
+ * Description	:
+ * Remarks	: Not reentrant because of static buffer
+ *****************************************************************************
+*/
+char *get_nameid_str(name_id_t *n)
+{
+	static char buffer[256];
+
+	if(!n)
+		return "<none>";
+
+	if(n->type == name_ord)
+	{
+		sprintf(buffer, "%d", n->name.i_name);
+		return buffer;
+	}
+	else if(n->type == name_str)
+	{
+		if(n->name.s_name->type == str_char)
+			return n->name.s_name->str.cstr;
+		else
+		{
+			strncpyWtoA(buffer, n->name.s_name->str.wstr, sizeof(buffer));
+			return buffer;
+		}
+	}
+	else
+		return "Hoooo, report this: wrong type in nameid";
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_memopt
+ * Syntax	: void dump_memopt(DWORD memopt)
+ * Input	:
+ *	memopt	- flag bits of the options set
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_memopt(DWORD memopt)
+{
+	printf("Memory/load options: ");
+	if(memopt & 0x0040)
+		printf("PRELOAD ");
+	else
+		printf("LOADONCALL ");
+	if(memopt & 0x0010)
+		printf("MOVEABLE ");
+	else
+		printf("FIXED ");
+	if(memopt & 0x0020)
+		printf("PURE ");
+	else
+		printf("IMPURE ");
+	if(memopt & 0x1000)
+		printf("DISCARDABLE");
+	printf("\n");
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_lvc
+ * Syntax	: void dump_lvc(lvc_t *l)
+ * Input	:
+ *	l	- pointer to lvc structure
+ * Output	:
+ * Description	: Dump language, version and characteristics
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_lvc(lvc_t *l)
+{
+	if(l->language)
+		printf("LANGUAGE %04x, %04x\n", l->language->id, l->language->sub);
+	else
+		printf("LANGUAGE <not set>\n");
+
+	if(l->version)
+		printf("VERSION %08lx\n", *(l->version));
+	else
+		printf("VERSION <not set>\n");
+
+	if(l->characts)
+		printf("CHARACTERISTICS %08lx\n", *(l->characts));
+	else
+		printf("CHARACTERISTICS <not set>\n");
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_raw_data
+ * Syntax	: void dump_raw_data(raw_data_t *d)
+ * Input	:
+ *	d	- Raw data descriptor
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_raw_data(raw_data_t *d)
+{
+	int n;
+	int i;
+	int j;
+
+	if(!d)
+	{
+		printf("<none>");
+		return;
+	}
+	printf("Rawdata size: %d\n", d->size);
+	if(debuglevel < 2)
+		return;
+
+	for(n = 0; n < d->size; n++)
+	{
+		if((n % 16) == 0)
+			if(n)
+			{
+				printf("- ");
+				for(i = 0; i < 16; i++)
+					printf("%c", isprint(d->data[n-16+i]) ? d->data[n-16+i] : '.');
+				printf("\n%08x: ", n);
+			}
+			else
+				printf("%08x: ", n);
+		printf("%02x ", d->data[n] & 0xff);
+	}
+	printf("- ");
+	j = d->size % 16;
+	if(!j)
+		j = 16;
+	for(i = 0; i < j; i++)
+		printf("%c", isprint(d->data[n-j+i]) ? d->data[n-j+i] : '.');
+	printf("\n");
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_accelerator
+ * Syntax	: void dump_accelerator(resource_t *acc)
+ * Input	:
+ *	acc	- Accelerator resource descriptor
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_accelerator(accelerator_t *acc)
+{
+	event_t *ev = acc->events;
+
+	dump_memopt(acc->memopt);
+	dump_lvc(&(acc->lvc));
+
+	printf("Events: %s\n", ev ? "" : "<none>");
+	while(ev)
+	{
+		printf("Key=");
+		if(isprint(ev->key))
+			printf("\"%c\"", ev->key);
+		else if(iscntrl(ev->key))
+			printf("\"^%c\"", ev->key +'@');
+		else
+			printf("\\x%02x", ev->key & 0xff);
+
+		printf(" Id=%d flags=%04x\n", ev->id, ev->flags);
+		ev = ev->next;
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_cursor
+ * Syntax	: void dump_cursor(cursor_t *cur)
+ * Input	:
+ *	cur	- Cursor resource descriptor
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_cursor(cursor_t *cur)
+{
+	printf("Id: %d\n", cur->id);
+	printf("Width: %d\n", cur->width);
+	printf("Height: %d\n", cur->height);
+	printf("X Hotspot: %d\n", cur->xhot);
+	printf("Y Hotspot: %d\n", cur->yhot);
+	dump_raw_data(cur->data);
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_cursor_group
+ * Syntax	: void dump_cursor_group(cursor_group_t *cur)
+ * Input	:
+ *	cur	- Cursor group resource descriptor
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_cursor_group(cursor_group_t *curg)
+{
+	dump_memopt(curg->memopt);
+	printf("There are %d cursors in this group\n", curg->ncursor);
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_icon
+ * Syntax	: void dump_icon(icon_t *ico)
+ * Input	:
+ *	ico	- Icon resource descriptor
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_icon(icon_t *ico)
+{
+	printf("Id: %d\n", ico->id);
+	printf("Width: %d\n", ico->width);
+	printf("Height: %d\n", ico->height);
+	printf("NColor: %d\n", ico->nclr);
+	printf("NPlanes: %d\n", ico->planes);
+	printf("NBits: %d\n", ico->bits);
+	dump_raw_data(ico->data);
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_icon_group
+ * Syntax	: void dump_icon_group(icon_group_t *ico)
+ * Input	:
+ *	ico	- Icon group resource descriptor
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_icon_group(icon_group_t *icog)
+{
+	dump_memopt(icog->memopt);
+	printf("There are %d icons in this group\n", icog->nicon);
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_font
+ * Syntax	: void dump_font(font_t *fnt)
+ * Input	:
+ *	fnt	- Font resource descriptor
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_font(font_t *fnt)
+{
+	dump_memopt(fnt->memopt);
+	dump_raw_data(fnt->data);
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_bitmap
+ * Syntax	: void dump_bitmap(bitmap_t *bmp)
+ * Input	:
+ *	bmp	- Bitmap resource descriptor
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_bitmap(bitmap_t *bmp)
+{
+	dump_memopt(bmp->memopt);
+	dump_raw_data(bmp->data);
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_rcdata
+ * Syntax	: void dump_rcdata(rcdata_t *rdt)
+ * Input	:
+ *	rdt	- RCData resource descriptor
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_rcdata(rcdata_t *rdt)
+{
+	dump_memopt(rdt->memopt);
+	dump_raw_data(rdt->data);
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_user
+ * Syntax	: void dump_user(user_t *usr)
+ * Input	:
+ *	usr	- User resource descriptor
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_user(user_t *usr)
+{
+	dump_memopt(usr->memopt);
+	printf("Class %s\n", get_nameid_str(usr->type));
+	dump_raw_data(usr->data);
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_messagetable
+ * Syntax	: void dump_messagetable(messagetable_t *msg)
+ * Input	:
+ *	msg	- Messagetable resource descriptor
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_messagetable(messagetable_t *msg)
+{
+	dump_raw_data(msg->data);
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_stringtable
+ * Syntax	: void dump_stringtable(stringtable_t *stt)
+ * Input	:
+ *	stt	- Stringtable resource descriptor
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_stringtable(stringtable_t *stt)
+{
+	int i;
+	for(; stt; stt = stt->next)
+	{
+		printf("{\n");
+		dump_memopt(stt->memopt);
+		dump_lvc(&(stt->lvc));
+		for(i = 0; i < stt->nentries; i++)
+		{
+			printf("Id=%-5d (%d) ", stt->idbase+i, stt->entries[i].id);
+			if(stt->entries[i].str)
+				print_string(stt->entries[i].str);
+			else
+				printf("<none>");
+			printf("\n");
+		}
+		printf("}\n");
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_control
+ * Syntax	: void dump_control(control_t *ctrl)
+ * Input	:
+ *	ctrl	- Control resource descriptor
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_control(control_t *ctrl)
+{
+	printf("Control {\n\tClass: %s\n", get_nameid_str(ctrl->ctlclass));
+	printf("\tText: "); print_string(ctrl->title); printf("\n");
+	printf("\tId: %d\n", ctrl->id);
+	printf("\tx, y, w, h: %d, %d, %d, %d\n", ctrl->x, ctrl->y, ctrl->width, ctrl->height);
+	if(ctrl->gotstyle)
+		printf("\tStyle: %08lx\n", ctrl->style);
+	if(ctrl->gotexstyle)
+		printf("\tExStyle: %08lx\n", ctrl->exstyle);
+	if(ctrl->gothelpid)
+		printf("\tHelpid: %ld\n", ctrl->helpid);
+	if(ctrl->extra)
+	{
+		printf("\t");
+		dump_raw_data(ctrl->extra);
+	}
+	printf("}\n");
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_dialog
+ * Syntax	: void dump_dialog(dialog_t *dlg)
+ * Input	:
+ *	dlg	- Dialog resource descriptor
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_dialog(dialog_t *dlg)
+{
+	control_t *c = dlg->controls;
+
+	dump_memopt(dlg->memopt);
+	dump_lvc(&(dlg->lvc));
+	printf("x, y, w, h: %d, %d, %d, %d\n", dlg->x, dlg->y, dlg->width, dlg->height);
+	if(dlg->gotstyle)
+		printf("Style: %08lx\n", dlg->style);
+	if(dlg->gotexstyle)
+		printf("ExStyle: %08lx\n", dlg->exstyle);
+	printf("Menu: %s\n", get_nameid_str(dlg->menu));
+	printf("Class: %s\n", get_nameid_str(dlg->dlgclass));
+	printf("Title: "); print_string(dlg->title); printf("\n");
+	printf("Font: ");
+	if(!dlg->font)
+		printf("<none>\n");
+	else
+	{
+		printf("%d, ", dlg->font->size);
+		print_string(dlg->font->name);
+		printf("\n");
+	}
+	while(c)
+	{
+		dump_control(c);
+		c = c->next;
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_dialogex
+ * Syntax	: void dump_dialogex(dialogex_t *dlgex)
+ * Input	:
+ *	dlgex	- DialogEx resource descriptor
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_dialogex(dialogex_t *dlgex)
+{
+	control_t *c = dlgex->controls;
+
+	dump_memopt(dlgex->memopt);
+	dump_lvc(&(dlgex->lvc));
+	printf("x, y, w, h: %d, %d, %d, %d\n", dlgex->x, dlgex->y, dlgex->width, dlgex->height);
+	if(dlgex->gotstyle)
+		printf("Style: %08lx\n", dlgex->style);
+	if(dlgex->gotexstyle)
+		printf("ExStyle: %08lx\n", dlgex->exstyle);
+	if(dlgex->gothelpid)
+		printf("Helpid: %ld\n", dlgex->helpid);
+	printf("Menu: %s\n", get_nameid_str(dlgex->menu));
+	printf("Class: %s\n", get_nameid_str(dlgex->dlgclass));
+	printf("Title: "); print_string(dlgex->title); printf("\n");
+	printf("Font: ");
+	if(!dlgex->font)
+		printf("<none>\n");
+	else
+	{
+		printf("%d, ", dlgex->font->size);
+		print_string(dlgex->font->name);
+		printf(", %d, %d\n", dlgex->font->weight, dlgex->font->italic);
+	}
+	while(c)
+	{
+		dump_control(c);
+		c = c->next;
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_menu_item
+ * Syntax	: void dump_menu_item(menu_item_t *item)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_menu_item(menu_item_t *item)
+{
+	while(item)
+	{
+		if(item->popup)
+		{
+			printf("POPUP ");
+			print_string(item->name);
+			printf("\n");
+			dump_menu_item(item->popup);
+		}
+		else
+		{
+			printf("MENUITEM ");
+			if(item->name)
+			{
+				print_string(item->name);
+				printf(", %d, %08lx", item->id, item->state);
+			}
+			else
+				printf("SEPARATOR");
+			printf("\n");
+		}
+		item = item->next;
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_menu
+ * Syntax	: void dump_menu(menu_t *men)
+ * Input	:
+ *	men	- Menu resource descriptor
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_menu(menu_t *men)
+{
+	dump_memopt(men->memopt);
+	dump_lvc(&(men->lvc));
+	dump_menu_item(men->items);
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_menuex_item
+ * Syntax	: void dump_menuex_item(menuex_item_t *item)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_menuex_item(menuex_item_t *item)
+{
+	while(item)
+	{
+		if(item->popup)
+		{
+			printf("POPUP ");
+			print_string(item->name);
+			if(item->gotid)
+				printf(", Id=%d", item->id);
+			if(item->gottype)
+				printf(", Type=%ld", item->type);
+			if(item->gotstate)
+				printf(", State=%08lx", item->state);
+			if(item->gothelpid)
+				printf(", HelpId=%d", item->helpid);
+			printf("\n");
+			dump_menuex_item(item->popup);
+		}
+		else
+		{
+			printf("MENUITEM ");
+			if(item->name)
+			{
+				print_string(item->name);
+				if(item->gotid)
+					printf(", Id=%d", item->id);
+				if(item->gottype)
+					printf(", Type=%ld", item->type);
+				if(item->gotstate)
+					printf(", State=%08lx", item->state);
+				if(item->gothelpid)
+					printf(", HelpId=%d", item->helpid);
+			}
+			else
+				printf("SEPARATOR");
+			printf("\n");
+		}
+		item = item->next;
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_menuex
+ * Syntax	: void dump_menuex(dialogex_t *menex)
+ * Input	:
+ *	menex	- MenuEx resource descriptor
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_menuex(menuex_t *menex)
+{
+	dump_memopt(menex->memopt);
+	dump_lvc(&(menex->lvc));
+	dump_menuex_item(menex->items);
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_ver_value
+ * Syntax	: void dump_ver_value(ver_value_t *val)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_ver_value(ver_value_t *val)
+{
+	extern void dump_ver_block(ver_block_t *);
+	if(val->type == val_str)
+	{
+		printf("VALUE ");
+		print_string(val->key);
+		printf(" ");
+		print_string(val->value.str);
+		printf("\n");
+	}
+	else if(val->type == val_words)
+	{
+		int i;
+		printf("VALUE");
+		print_string(val->key);
+		for(i = 0; i < val->value.words->nwords; i++)
+			printf(" %04x", val->value.words->words[i]);
+		printf("\n");
+	}
+	else if(val->type == val_block)
+	{
+		dump_ver_block(val->value.block);
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_ver_block
+ * Syntax	: void dump_ver_block(ver_block_t *blk)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_ver_block(ver_block_t *blk)
+{
+	ver_value_t *val = blk->values;
+	printf("BLOCK ");
+	print_string(blk->name);
+	printf("\n{\n");
+	while(val)
+	{
+		dump_ver_value(val);
+		val = val->next;
+	}
+	printf("}\n");
+}
+
+/*
+ *****************************************************************************
+ * Function	: dump_versioninfo
+ * Syntax	: void dump_versioninfo(versioninfo_t *ver)
+ * Input	:
+ *	ver	- Versioninfo resource descriptor
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_versioninfo(versioninfo_t *ver)
+{
+	ver_block_t *blk = ver->blocks;
+
+	if(ver->gotit.fv)
+		printf("FILEVERSION %04x, %04x, %04x, %04x\n",
+			ver->filever_maj1,
+			ver->filever_maj2,
+			ver->filever_min1,
+			ver->filever_min2);
+	if(ver->gotit.pv)
+		printf("PRODUCTVERSION %04x, %04x, %04x, %04x\n",
+			ver->prodver_maj1,
+			ver->prodver_maj2,
+			ver->prodver_min1,
+			ver->prodver_min2);
+	if(ver->gotit.fo)
+		printf("FILEOS %08x\n", ver->fileos);
+	if(ver->gotit.ff)
+		printf("FILEFLAGS %08x\n", ver->fileflags);
+	if(ver->gotit.ffm)
+		printf("FILEFLAGSMASK %08x\n", ver->fileflagsmask);
+	if(ver->gotit.ft)
+		printf("FILETYPE %08x\n", ver->filetype);
+	if(ver->gotit.fst)
+		printf("FILESUBTYPE %08x\n", ver->filesubtype);
+	while(blk)
+	{
+		dump_ver_block(blk);
+		blk = blk->next;
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	:
+ * Syntax	:
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+/*
+ *****************************************************************************
+ * Function	: dump_resources
+ * Syntax	: void dump_resources(resource_t *top)
+ * Input	:
+ *	top	- Top of the resource tree
+ * Output	:
+ *	nop
+ * Description	: Dump the parsed resource-tree to stdout
+ * Remarks	:
+ *****************************************************************************
+*/
+void dump_resources(resource_t *top)
+{
+	printf("Internal resource-tree dump:\n");
+	while(top)
+	{
+		printf("Resource: %s\nId: %s\n",
+		       get_typename(top),
+		       get_nameid_str(top->name));
+		switch(top->type)
+		{
+		case res_acc:
+			dump_accelerator(top->res.acc);
+			break;
+		case res_bmp:
+			dump_bitmap(top->res.bmp);
+			break;
+		case res_cur:
+			dump_cursor(top->res.cur);
+			break;
+		case res_curg:
+			dump_cursor_group(top->res.curg);
+			break;
+		case res_dlg:
+			dump_dialog(top->res.dlg);
+			break;
+		case res_dlgex:
+			dump_dialogex(top->res.dlgex);
+			break;
+		case res_fnt:
+			dump_font(top->res.fnt);
+			break;
+		case res_icog:
+			dump_icon_group(top->res.icog);
+			break;
+		case res_ico:
+			dump_icon(top->res.ico);
+			break;
+		case res_men:
+			dump_menu(top->res.men);
+			break;
+		case res_menex:
+			dump_menuex(top->res.menex);
+			break;
+		case res_rdt:
+			dump_rcdata(top->res.rdt);
+			break;
+		case res_stt:
+			dump_stringtable(top->res.stt);
+			break;
+		case res_usr:
+			dump_user(top->res.usr);
+			break;
+		case res_msg:
+			dump_messagetable(top->res.msg);
+			break;
+		case res_ver:
+			dump_versioninfo(top->res.ver);
+			break;
+		default:
+			printf("Report this: Unknown resource type parsed %08x\n", top->type);
+		}
+		printf("\n");
+		top = top->next;
+	}
+}
+
diff --git a/tools/wrc/dumpres.h b/tools/wrc/dumpres.h
new file mode 100644
index 0000000..75e9650
--- /dev/null
+++ b/tools/wrc/dumpres.h
@@ -0,0 +1,18 @@
+/*
+ * Dump resource prototypes
+ *
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ */
+
+#ifndef __WRC_DUMPRES_H
+#define __WRC_DUMPRES_H
+
+#ifndef __WRC_WRCTYPES_H
+#include "wrctypes.h"
+#endif
+
+char *get_typename(resource_t* r);
+void dump_resources(resource_t *top);
+
+#endif
diff --git a/tools/wrc/genres.c b/tools/wrc/genres.c
new file mode 100644
index 0000000..b9e831c
--- /dev/null
+++ b/tools/wrc/genres.c
@@ -0,0 +1,1668 @@
+/*
+ * Generate .res format from a resource-tree
+ *
+ * Copyright 1998 Bertho A. Stultiens
+ *
+ * 25-May-1998 BS	- Added simple unicode -> char conversion for resource
+ *			  names in .s and .h files.  
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include <config.h>
+#include "wrc.h"
+#include "genres.h"
+#include "utils.h"
+
+#define SetResSize(res, tag)	*(DWORD *)&((res)->data[(tag)]) = \
+				(res)->size - *(DWORD *)&((res)->data[(tag)])
+
+res_t *new_res(void)
+{
+	res_t *r;
+	r = (res_t *)xmalloc(sizeof(res_t));
+	r->allocsize = RES_BLOCKSIZE;
+	r->size = 0;
+	r->data = (char *)xmalloc(RES_BLOCKSIZE);
+	return r;
+}
+
+res_t *grow_res(res_t *r, int add)
+{
+	r->allocsize += add;
+	r->data = (char *)xrealloc(r->data, r->allocsize);
+	return r;
+}
+
+/*
+ *****************************************************************************
+ * Function	: put_byte
+ *		  put_word
+ *		  put_dword
+ * Syntax	: void put_byte(res_t *res, unsigned c)
+ *		  void put_word(res_t *res, unsigned w)
+ *		  void put_dword(res_t *res, unsigned d)
+ * Input	:
+ *	res	- Binary resource to put the data in
+ *	c, w, d	- Data to put
+ * Output	: nop
+ * Description	: Put primitives that put an item in the binary resource.
+ *		  The data array grows automatically.
+ * Remarks	:
+ *****************************************************************************
+*/
+void put_byte(res_t *res, unsigned c)
+{
+	if(res->allocsize - res->size < sizeof(char))
+		grow_res(res, RES_BLOCKSIZE);
+	*(char *)&(res->data[res->size]) = (char)c;
+	res->size += sizeof(char);
+}
+
+void put_word(res_t *res, unsigned w)
+{
+	if(res->allocsize - res->size < sizeof(WORD))
+		grow_res(res, RES_BLOCKSIZE);
+	*(WORD *)&(res->data[res->size]) = (WORD)w;
+	res->size += sizeof(WORD);
+}
+
+void put_dword(res_t *res, unsigned d)
+{
+	if(res->allocsize - res->size < sizeof(DWORD))
+		grow_res(res, RES_BLOCKSIZE);
+	*(DWORD *)&(res->data[res->size]) = (DWORD)d;
+	res->size += sizeof(DWORD);
+}
+
+void put_pad(res_t *res)
+{
+	while(res->size & 0x3)
+		put_byte(res, 0);
+}
+
+/*
+ *****************************************************************************
+ * Function	: string_to_upper
+ * Syntax	: void string_to_upper(string_t *str)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	: FIXME: codepages...
+ *****************************************************************************
+*/
+void string_to_upper(string_t *str)
+{
+	if(str->type == str_char)
+	{
+		char *cptr = str->str.cstr;
+		for(; *cptr; cptr++)
+			*cptr = (char)toupper(*cptr);
+	}
+	else if(str->type == str_unicode)
+	{
+		short *sptr = str->str.wstr;
+		for(; *sptr; sptr++)
+			if(isalpha(*sptr))
+				*sptr = (short)toupper(*sptr);
+	}
+	else
+	{
+		internal_error(__FILE__, __LINE__, "Invalid string type %d", str->type);
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: put_string
+ * Syntax	: void put_string(res_t *res, string_t *str, enum str_e type,
+ *				  int isterm)
+ * Input	:
+ *	res	- Binary resource to put the data in
+ *	str	- String to put
+ *	type	- Data has to be written in either str_char or str_unicode
+ *	isterm	- The string is '\0' terminated (disregard the string's
+ *		  size member)
+ * Output	: nop
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void put_string(res_t *res, string_t *str, enum str_e type, int isterm)
+{
+	int cnt;
+	int c = !0;
+	assert(res != NULL);
+	assert(str != NULL);
+	if(!isterm && str->size == 0)
+	{
+		warning("String length is zero, not written");
+		return;
+	}
+
+	if(str->type == str_unicode && type == str_unicode)
+	{
+		for(cnt = 0; cnt < str->size; cnt++)
+		{
+			c = str->str.wstr[cnt];
+			put_word(res, c);
+			if(isterm && !c)
+				break;
+		}
+		if(isterm && (str->size == 0 || (cnt == str->size && c)))
+			put_word(res, 0);
+	}
+	else if(str->type == str_char && type == str_char)
+	{
+		for(cnt = 0; cnt < str->size; cnt++)
+		{
+			c = str->str.cstr[cnt];
+			put_byte(res, c);
+			if(isterm && !c)
+				break;
+		}
+		if(isterm && (str->size == 0 || (cnt == str->size && c)))
+			put_byte(res, 0);
+	}
+	else if(str->type == str_unicode && type == str_char)
+	{
+		for(cnt = 0; cnt < str->size; cnt++)
+		{
+			c = str->str.wstr[cnt];
+			put_byte(res, c);
+			if(isterm && !c)
+				break;
+		}
+		if(isterm && (str->size == 0 || (cnt == str->size && c)))
+			put_byte(res, 0);
+	}
+	else /* str->type == str_char && type == str_unicode */
+	{
+		for(cnt = 0; cnt < str->size; cnt++)
+		{
+			c = str->str.cstr[cnt];
+			put_word(res, c & 0xff);
+			if(isterm && !c)
+				break;
+		}
+		if(isterm && (str->size == 0 || (cnt == str->size && c)))
+			put_word(res, 0);
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: put_name_id
+ * Syntax	: void put_name_id(res_t *res, name_id_t *nid, int upcase)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void put_name_id(res_t *res, name_id_t *nid, int upcase)
+{
+	if(nid->type == name_ord)
+	{
+		if(win32)
+			put_word(res, 0xffff);
+		else
+			put_byte(res, 0xff);
+		put_word(res, (WORD)nid->name.i_name);
+	}
+	else if(nid->type == name_str)
+	{
+		if(upcase)
+			string_to_upper(nid->name.s_name);
+		put_string(res, nid->name.s_name, win32 ? str_unicode : str_char, TRUE);
+	}
+	else
+	{
+		internal_error(__FILE__, __LINE__, "Invalid name_id type %d", nid->type);
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: put_lvc
+ * Syntax	: void put_lvc(res_t *res, lvc_t *lvc)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void put_lvc(res_t *res, lvc_t *lvc)
+{
+	if(lvc && lvc->language)
+		put_word(res, MAKELANGID(lvc->language->id, lvc->language->sub));
+	else
+		put_word(res, 0);	/* Neutral */
+	if(lvc && lvc->version)
+		put_dword(res, *(lvc->version));
+	else
+		put_dword(res, 0);
+	if(lvc && lvc->characts)
+		put_dword(res, *(lvc->characts));
+	else
+		put_dword(res, 0);
+}
+
+/*
+ *****************************************************************************
+ * Function	: put_raw_data
+ * Syntax	: void put_raw_data(res_t *res, raw_data_t *raw, int offset)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void put_raw_data(res_t *res, raw_data_t *raw, int offset)
+{
+	int wsize = raw->size - offset;
+	if(res->allocsize - res->size < wsize)
+		grow_res(res, wsize);
+	memcpy(&(res->data[res->size]), raw->data + offset, wsize);
+	res->size += wsize;
+}
+
+/*
+ *****************************************************************************
+ * Function	: put_res_header
+ * Syntax	: intput_res_header(res_t *res, int type, name_id_t *ntype,
+ *				    name_id_t *name, DWORD memopt, lvc_t *lvc)
+ *
+ * Input	:
+ *	res	- Binary resource descriptor to write to
+ *	type	- Resource identifier (if ntype == NULL)
+ *	ntype	- Name id of type
+ *	name	- Resource's name
+ *	memopt	- Resource's memory options to write
+ *	lvc	- Language, version and characteristics (win32 only)
+ * Output	: An index to the resource size field. The resource size field
+ *		  contains the header size upon exit.
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+int put_res_header(res_t *res, int type, name_id_t *ntype, name_id_t *name,
+		      DWORD memopt, lvc_t *lvc)
+{
+	if(win32)
+	{
+		put_dword(res, 0);		/* We will overwrite these later */
+		put_dword(res, 0);
+		if(!ntype)
+		{
+			put_word(res, 0xffff);		/* ResType */
+			put_word(res, type);
+		}
+		else
+			put_name_id(res, ntype, TRUE);
+		put_name_id(res, name, TRUE);	/* ResName */
+		put_pad(res);
+		put_dword(res, 0);		/* DataVersion */
+		put_word(res, memopt);		/* Memory options */
+		put_lvc(res, lvc);		/* Language, version and characts */
+		((DWORD *)res->data)[0] = res->size;	/* Set preliminary resource */
+		((DWORD *)res->data)[1] = res->size;	/* Set HeaderSize */
+		res->dataidx = res->size;
+		return 0;
+	}
+	else /* win16 */
+	{
+		int tag;
+		if(!ntype)
+		{
+			put_byte(res, 0xff);		/* ResType */
+			put_word(res, type);
+		}
+		else
+			put_name_id(res, ntype, TRUE);
+		put_name_id(res, name, TRUE);	/* ResName */
+		put_word(res, memopt);		/* Memory options */
+		tag = res->size;
+		put_dword(res, 0);		/* ResSize overwritten later*/
+		*(DWORD *)&(res->data[tag]) = res->size;
+		res->dataidx = res->size;
+		return tag;
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: accelerator2res
+ * Syntax	: res_t *accelerator2res(name_id_t *name, accelerator_t *acc)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	acc	- The accelerator descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *accelerator2res(name_id_t *name, accelerator_t *acc)
+{
+	int restag;
+	res_t *res;
+	event_t *ev;
+	assert(name != NULL);
+	assert(acc != NULL);
+
+	ev = acc->events;
+	res = new_res();
+	if(win32)
+	{
+		restag = put_res_header(res, WRC_RT_ACCELERATOR, NULL, name, acc->memopt, &(acc->lvc));
+		while(ev)
+		{
+			put_word(res, ev->flags | (ev->next ? 0 : 0x80));
+			put_word(res, ev->key);
+			put_word(res, ev->id);
+			put_word(res, 0);	/* Padding */
+			ev = ev->next;
+		}
+		put_pad(res);
+	}
+	else /* win16 */
+	{
+		restag = put_res_header(res, WRC_RT_ACCELERATOR, NULL, name, acc->memopt, NULL);
+		while(ev)
+		{
+			put_byte(res, ev->flags | (ev->next ? 0 : 0x80));
+			put_word(res, ev->key);
+			put_word(res, ev->id);
+			ev = ev->next;
+		}
+	}
+	/* Set ResourceSize */
+	SetResSize(res, restag);
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: dialog2res
+ * Syntax	: res_t *dialog2res(name_id_t *name, dialog_t *dlg)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	dlg	- The dialog descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *dialog2res(name_id_t *name, dialog_t *dlg)
+{
+	int restag;
+	res_t *res;
+	control_t *ctrl;
+	int tag_nctrl;
+	int nctrl = 0;
+	assert(name != NULL);
+	assert(dlg != NULL);
+
+	ctrl = dlg->controls;
+	res = new_res();
+	if(win32)
+	{
+		restag = put_res_header(res, WRC_RT_DIALOG, NULL, name, dlg->memopt, &(dlg->lvc));
+
+		put_dword(res, dlg->style);
+		put_dword(res, dlg->gotexstyle ? dlg->exstyle : 0);
+		tag_nctrl = res->size;
+		put_word(res, 0);		/* Number of controls */
+		put_word(res, dlg->x);
+		put_word(res, dlg->y);
+		put_word(res, dlg->width);
+		put_word(res, dlg->height);
+		if(dlg->menu)
+			put_name_id(res, dlg->menu, TRUE);
+		else
+			put_word(res, 0);
+		if(dlg->dlgclass)
+			put_name_id(res, dlg->dlgclass, TRUE);
+		else
+			put_word(res, 0);
+		if(dlg->title)
+			put_string(res, dlg->title, str_unicode, TRUE);
+		else
+			put_word(res, 0);
+		if(dlg->font)
+		{
+			put_word(res, dlg->font->size);
+			put_string(res, dlg->font->name, str_unicode, TRUE);
+		}
+
+		put_pad(res);
+		while(ctrl)
+		{
+			/* FIXME: what is default control style? */
+			put_dword(res, ctrl->gotstyle ? ctrl->style : WS_CHILD);
+			put_dword(res, ctrl->gotexstyle ? ctrl->exstyle : 0);
+			put_word(res, ctrl->x);
+			put_word(res, ctrl->y);
+			put_word(res, ctrl->width);
+			put_word(res, ctrl->height);
+			put_word(res, ctrl->id);
+			if(ctrl->ctlclass)
+				put_name_id(res, ctrl->ctlclass, TRUE);
+			else
+				internal_error(__FILE__, __LINE__, "Control has no control-class");
+			if(ctrl->title)
+				put_string(res, ctrl->title, str_unicode, TRUE);
+			else
+				put_word(res, 0);
+			if(ctrl->extra)
+			{
+				put_word(res, ctrl->extra->size+2);
+				put_pad(res);
+				put_raw_data(res, ctrl->extra, 0);
+			}
+			else
+				put_word(res, 0);
+
+			if(ctrl->next)
+				put_pad(res);
+			nctrl++;
+			ctrl = ctrl->next;
+		}
+		/* Set number of controls */
+		*(WORD *)&((char *)res->data)[tag_nctrl] = (WORD)nctrl;
+	}
+	else /* win16 */
+	{
+		restag = put_res_header(res, WRC_RT_DIALOG, NULL, name, dlg->memopt, NULL);
+
+		put_dword(res, dlg->gotstyle ? dlg->style : WS_POPUPWINDOW);
+		tag_nctrl = res->size;
+		put_byte(res, 0);		/* Number of controls */
+		put_word(res, dlg->x);
+		put_word(res, dlg->y);
+		put_word(res, dlg->width);
+		put_word(res, dlg->height);
+		if(dlg->menu)
+			put_name_id(res, dlg->menu, TRUE);
+		else
+			put_byte(res, 0);
+		if(dlg->dlgclass)
+			put_name_id(res, dlg->dlgclass, TRUE);
+		else
+			put_byte(res, 0);
+		if(dlg->title)
+			put_string(res, dlg->title, str_char, TRUE);
+		else
+			put_byte(res, 0);
+		if(dlg->font)
+		{
+			put_word(res, dlg->font->size);
+			put_string(res, dlg->font->name, str_char, TRUE);
+		}
+
+		while(ctrl)
+		{
+			put_word(res, ctrl->x);
+			put_word(res, ctrl->y);
+			put_word(res, ctrl->width);
+			put_word(res, ctrl->height);
+			put_word(res, ctrl->id);
+			put_dword(res, ctrl->gotstyle ? ctrl->style : WS_CHILD);
+			if(ctrl->ctlclass)
+			{
+				if(ctrl->ctlclass->type == name_ord
+				&& ctrl->ctlclass->name.i_name >= 0x80
+				&& ctrl->ctlclass->name.i_name <= 0x85)
+					put_byte(res, ctrl->ctlclass->name.i_name);
+				else if(ctrl->ctlclass->type == name_str)
+					put_name_id(res, ctrl->ctlclass, FALSE);
+				else
+					error("Unknown control-class %04x", ctrl->ctlclass->name.i_name);
+			}
+			else
+				internal_error(__FILE__, __LINE__, "Control has no control-class");
+			if(ctrl->title)
+				put_string(res, ctrl->title, str_char, TRUE);
+			else
+				put_byte(res, 0);
+
+			/* FIXME: What is this extra byte doing here? */
+			put_byte(res, 0);
+			
+			nctrl++;
+			ctrl = ctrl->next;
+		}
+		/* Set number of controls */
+		((char *)res->data)[tag_nctrl] = (char)nctrl;
+	}
+	/* Set ResourceSize */
+	SetResSize(res, restag);
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: dialogex2res
+ * Syntax	: res_t *dialogex2res(name_id_t *name, dialogex_t *dlgex)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	dlgex	- The dialogex descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *dialogex2res(name_id_t *name, dialogex_t *dlgex)
+{
+	int restag;
+	res_t *res;
+	control_t *ctrl;
+	int tag_nctrl;
+	int nctrl = 0;
+	assert(name != NULL);
+	assert(dlgex != NULL);
+
+	ctrl = dlgex->controls;
+	res = new_res();
+	if(win32)
+	{
+		restag = put_res_header(res, WRC_RT_DIALOG, NULL, name, dlgex->memopt, &(dlgex->lvc));
+
+		/* FIXME: MS doc says thet the first word must contain 0xffff
+		 * and the second 0x0001 to signal a DLGTEMPLATEEX. Borland's
+		 * compiler reverses the two words.
+		 * I don't know which one to choose, but I write it as Mr. B
+		 * writes it.
+		 */
+		put_word(res, 1);		/* Signature */
+		put_word(res, 0xffff);		/* DlgVer */
+		put_dword(res, dlgex->gothelpid ? dlgex->helpid : 0);
+		put_dword(res, dlgex->gotexstyle ? dlgex->exstyle : 0);
+		put_dword(res, dlgex->gotstyle ? dlgex->style : WS_POPUPWINDOW);
+		tag_nctrl = res->size;
+		put_word(res, 0);		/* Number of controls */
+		put_word(res, dlgex->x);
+		put_word(res, dlgex->y);
+		put_word(res, dlgex->width);
+		put_word(res, dlgex->height);
+		if(dlgex->menu)
+			put_name_id(res, dlgex->menu, TRUE);
+		else
+			put_word(res, 0);
+		if(dlgex->dlgclass)
+			put_name_id(res, dlgex->dlgclass, TRUE);
+		else
+			put_word(res, 0);
+		if(dlgex->title)
+			put_string(res, dlgex->title, str_unicode, TRUE);
+		else
+			put_word(res, 0);
+		if(dlgex->font)
+		{
+			put_word(res, dlgex->font->size);
+			put_word(res, dlgex->font->weight);
+			/* FIXME: ? TRUE should be sufficient to say that its
+			 * italic, but Borland's compiler says its 0x0101.
+			 * I just copy it here, and hope for the best.
+			 */
+			put_word(res, dlgex->font->italic ? 0x0101 : 0);
+			put_string(res, dlgex->font->name, str_unicode, TRUE);
+		}
+
+		put_pad(res);
+		while(ctrl)
+		{
+			put_dword(res, ctrl->gothelpid ? ctrl->helpid : 0);
+			put_dword(res, ctrl->gotexstyle ? ctrl->exstyle : 0);
+			/* FIXME: what is default control style? */
+			put_dword(res, ctrl->gotstyle ? ctrl->style : WS_CHILD | WS_VISIBLE);
+			put_word(res, ctrl->x);
+			put_word(res, ctrl->y);
+			put_word(res, ctrl->width);
+			put_word(res, ctrl->height);
+			put_word(res, ctrl->id);
+			/* FIXME: Pad is _NOT_ documented!?! */
+			put_pad(res);
+			if(ctrl->ctlclass)
+				put_name_id(res, ctrl->ctlclass, TRUE);
+			else
+				internal_error(__FILE__, __LINE__, "Control has no control-class");
+			if(ctrl->title)
+				put_string(res, ctrl->title, str_unicode, TRUE);
+			else
+				put_word(res, 0);
+			if(ctrl->extra)
+			{
+				put_pad(res);
+				put_word(res, ctrl->extra->size);
+				put_raw_data(res, ctrl->extra, 0);
+			}
+			else
+				put_word(res, 0);
+
+			put_pad(res);
+			nctrl++;
+			ctrl = ctrl->next;
+		}
+		/* Set number of controls */
+		*(WORD *)&((char *)res->data)[tag_nctrl] = (WORD)nctrl;
+		/* Set ResourceSize */
+		SetResSize(res, restag);
+		put_pad(res);
+	}
+	else /* win16 */
+	{
+		/* Do not generate anything in 16-bit mode */
+		free(res->data);
+		free(res);
+		return NULL;
+	}
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: menuitem2res
+ * Syntax	: void menuitem2res(res_t *res, menu_item_t *item)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	: Self recursive
+ *****************************************************************************
+*/
+void menuitem2res(res_t *res, menu_item_t *menitem)
+{
+	menu_item_t *itm = menitem;
+	if(win32)
+	{
+		while(itm)
+		{
+			put_word(res, itm->state | (itm->popup ? MF_POPUP : 0) | (!itm->next ? MF_END : 0));
+			if(!itm->popup)
+				put_word(res, itm->id);
+			if(itm->name)
+				put_string(res, itm->name, str_unicode, TRUE);
+			else
+				put_word(res, 0);
+			if(itm->popup)
+				menuitem2res(res, itm->popup);
+			itm = itm->next;
+		}
+	}
+	else /* win16 */
+	{
+		while(itm)
+		{
+			put_word(res, itm->state | (itm->popup ? MF_POPUP : 0) | (!itm->next ? MF_END : 0));
+			if(!itm->popup)
+				put_word(res, itm->id);
+			if(itm->name)
+				put_string(res, itm->name, str_char, TRUE);
+			else
+				put_byte(res, 0);
+			if(itm->popup)
+				menuitem2res(res, itm->popup);
+			itm = itm->next;
+		}
+	}
+
+}
+
+/*
+ *****************************************************************************
+ * Function	: menu2res
+ * Syntax	: res_t *menu2res(name_id_t *name, menu_t *men)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	men	- The menu descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *menu2res(name_id_t *name, menu_t *men)
+{
+	int restag;
+	res_t *res;
+	assert(name != NULL);
+	assert(men != NULL);
+
+	res = new_res();
+	restag = put_res_header(res, WRC_RT_MENU, NULL, name, men->memopt, win32 ? &(men->lvc) : NULL);
+
+	put_dword(res, 0);		/* Menuheader: Version and HeaderSize */
+	menuitem2res(res, men->items);
+	/* Set ResourceSize */
+	SetResSize(res, restag);
+	if(win32)
+		put_pad(res);
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: menuexitem2res
+ * Syntax	: void menuexitem2res(res_t *res, menuex_item_t *item)
+ * Input	:
+ * Output	: nop
+ * Description	:
+ * Remarks	: Self recursive
+ *****************************************************************************
+*/
+void menuexitem2res(res_t *res, menuex_item_t *menitem)
+{
+	menuex_item_t *itm = menitem;
+	assert(win32 != 0);
+	while(itm)
+	{
+		put_dword(res, itm->gottype ? itm->type : 0);
+		put_dword(res, itm->gotstate ? itm->state : 0);
+		put_dword(res, itm->gotid ? itm->id : 0);	/* FIXME: Docu. says word */
+		put_word(res, (itm->popup ? 0x01 : 0) | (!itm->next ? MF_END : 0));
+		if(itm->name)
+			put_string(res, itm->name, str_unicode, TRUE);
+		else
+			put_word(res, 0);
+		put_pad(res);
+		if(itm->popup)
+		{
+			put_dword(res, itm->gothelpid ? itm->helpid : 0);
+			menuexitem2res(res, itm->popup);
+		}
+		itm = itm->next;
+	}
+
+}
+
+/*
+ *****************************************************************************
+ * Function	: menuex2res
+ * Syntax	: res_t *menuex2res(name_id_t *name, menuex_t *menex)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	menex	- The menuex descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *menuex2res(name_id_t *name, menuex_t *menex)
+{
+	int restag;
+	res_t *res;
+	assert(name != NULL);
+	assert(menex != NULL);
+
+	res = new_res();
+	if(win32)
+	{
+		/* FIXME: Borland's rc compiler writes the default system's
+		 * language if none specified (0x406 for me that is). I believe
+		 * that this is a Borland bug (brc32 ver. 5.01), as the default
+		 * should be 0 (system default).
+		 */
+		restag = put_res_header(res, WRC_RT_MENU, NULL, name, menex->memopt, &(menex->lvc));
+
+		put_word(res, 1);		/* Menuheader: Version */
+		put_word(res, 4);		/* Offset */
+		put_dword(res, 0);		/* HelpId */
+		put_pad(res);
+		menuexitem2res(res, menex->items);
+		/* Set ResourceSize */
+		SetResSize(res, restag);
+		put_pad(res);
+	}
+	else /* win16 */
+	{
+		/* Do not generate anything in 16-bit mode */
+		free(res->data);
+		free(res);
+		return NULL;
+	}
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: cursorgroup2res
+ * Syntax	: res_t *cursorgroup2res(name_id_t *name, cursor_group_t *curg)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	curg	- The cursor descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *cursorgroup2res(name_id_t *name, cursor_group_t *curg)
+{
+	int restag;
+	res_t *res;
+	cursor_t *cur;
+	assert(name != NULL);
+	assert(curg != NULL);
+
+	res = new_res();
+	restag = put_res_header(res, WRC_RT_GROUP_CURSOR, NULL, name, curg->memopt, NULL);
+	if(win32)
+	{
+		/* FIXME: Borland's rc compiler writes the default system's
+		 * language if none specified (0x406 for me that is). I believe
+		 * that this is a Borland bug (brc32 ver. 5.01), as the default
+		 * should be 0 (system default).
+		 */
+
+		put_word(res, 0);	/* Reserved */
+		/* FIXME: The ResType in the NEWHEADER structure should
+		 * contain 14 according to the MS win32 doc. This is
+		 * not the case with the BRC compiler and I really doubt
+		 * the latter. Putting one here is compliant to win16 spec,
+		 * but who knows the true value?
+		 */
+		put_word(res, 2);	/* ResType */
+		put_word(res, curg->ncursor);
+#if 0
+		for(cur = curg->cursorlist; cur; cur = cur->next)
+#else
+		cur = curg->cursorlist;
+		while(cur->next)
+			cur = cur->next;
+		for(; cur; cur = cur->prev)
+#endif
+		{
+			put_word(res, cur->width);
+			/* FIXME: The height of a cursor is half the size of
+			 * the bitmap's height. BRC puts the height from the
+			 * BITMAPINFOHEADER here instead of the cursorfile's
+			 * height. MS doesn't seem to care...
+			 */
+			put_word(res, cur->height);
+			/* FIXME: The next two are reversed in BRC and I don't
+			 * know why. Probably a bug. But, we can safely ignore
+			 * it because win16 does not support color cursors.
+			 * A warning should have been generated by the parser.
+			 */
+			put_word(res, cur->planes);
+			put_word(res, cur->bits);
+			/* FIXME: The +4 is the hotspot in the cursor resource.
+			 * However, I cound not find this in the documentation.
+			 * The hotspot bytes must either be included or MS
+			 * doesn't care.
+			 */
+			put_dword(res, cur->data->size +4);
+			put_word(res, cur->id);
+		}
+	}
+	else /* win16 */
+	{
+		put_word(res, 0);	/* Reserved */
+		put_word(res, 2);	/* ResType */
+		put_word(res, curg->ncursor);
+#if 0
+		for(cur = curg->cursorlist; cur; cur = cur->next)
+#else
+		cur = curg->cursorlist;
+		while(cur->next)
+			cur = cur->next;
+		for(; cur; cur = cur->prev)
+#endif
+		{
+			put_word(res, cur->width);
+			/* FIXME: The height of a cursor is half the size of
+			 * the bitmap's height. BRC puts the height from the
+			 * BITMAPINFOHEADER here instead of the cursorfile's
+			 * height. MS doesn't seem to care...
+			 */
+			put_word(res, cur->height);
+			/* FIXME: The next two are reversed in BRC and I don't
+			 * know why. Probably a bug. But, we can safely ignore
+			 * it because win16 does not support color cursors.
+			 * A warning should have been generated by the parser.
+			 */
+			put_word(res, cur->planes);
+			put_word(res, cur->bits);
+			/* FIXME: The +4 is the hotspot in the cursor resource.
+			 * However, I cound not find this in the documentation.
+			 * The hotspot bytes must either be included or MS
+			 * doesn't care.
+			 */
+			put_dword(res, cur->data->size +4);
+			put_word(res, cur->id);
+		}
+	}
+	SetResSize(res, restag);	/* Set ResourceSize */
+	if(win32)
+		put_pad(res);
+
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: cursor2res
+ * Syntax	: res_t *cursor2res(cursor_t *cur)
+ * Input	:
+ *	cur	- The cursor descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *cursor2res(cursor_t *cur)
+{
+	int restag;
+	res_t *res;
+	name_id_t name;
+
+	assert(cur != NULL);
+
+	res = new_res();
+	name.type = name_ord;
+	name.name.i_name = cur->id;
+	/* FIXME: Borland's rc compiler writes the default system's
+	 * language if none specified (0x406 for me that is). I believe
+	 * that this is a Borland bug (brc32 ver. 5.01), as the default
+	 * should be 0 (system default).
+	 */
+	restag = put_res_header(res, WRC_RT_CURSOR, NULL, &name, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, NULL);
+	put_word(res, cur->xhot);
+	put_word(res, cur->yhot);
+	put_raw_data(res, cur->data, 0);
+
+	SetResSize(res, restag);	/* Set ResourceSize */
+	if(win32)
+		put_pad(res);
+
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: icongroup2res
+ * Syntax	: res_t *icongroup2res(name_id_t *name, icon_group_t *icog)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	icog	- The icon group descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *icongroup2res(name_id_t *name, icon_group_t *icog)
+{
+	int restag;
+	res_t *res;
+	icon_t *ico;
+	assert(name != NULL);
+	assert(icog != NULL);
+
+	res = new_res();
+	restag = put_res_header(res, WRC_RT_GROUP_ICON, NULL, name, icog->memopt, NULL);
+	if(win32)
+	{
+		/* FIXME: Borland's rc compiler writes the default system's
+		 * language if none specified (0x406 for me that is). I believe
+		 * that this is a Borland bug (brc32 ver. 5.01), as the default
+		 * should be 0 (system default).
+		 */
+
+		put_word(res, 0);	/* Reserved */
+		/* FIXME: The ResType in the NEWHEADER structure should
+		 * contain 14 according to the MS win32 doc. This is
+		 * not the case with the BRC compiler and I really doubt
+		 * the latter. Putting one here is compliant to win16 spec,
+		 * but who knows the true value?
+		 */
+		put_word(res, 1);	/* ResType */
+		put_word(res, icog->nicon);
+		for(ico = icog->iconlist; ico; ico = ico->next)
+		{
+			put_byte(res, ico->width);
+			put_byte(res, ico->height);
+			put_byte(res, ico->nclr);
+			put_byte(res, 0);	/* Reserved */
+			put_word(res, ico->planes);
+			put_word(res, ico->bits);
+			put_dword(res, ico->data->size);
+			put_word(res, ico->id);
+		}
+	}
+	else /* win16 */
+	{
+		put_word(res, 0);	/* Reserved */
+		put_word(res, 1);	/* ResType */
+		put_word(res, icog->nicon);
+		for(ico = icog->iconlist; ico; ico = ico->next)
+		{
+			put_byte(res, ico->width);
+			put_byte(res, ico->height);
+			put_byte(res, ico->nclr);
+			put_byte(res, 0);	/* Reserved */
+			put_word(res, ico->planes);
+			put_word(res, ico->bits);
+			put_dword(res, ico->data->size);
+			put_word(res, ico->id);
+		}
+	}
+	SetResSize(res, restag);	/* Set ResourceSize */
+	if(win32)
+		put_pad(res);
+
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: icon2res
+ * Syntax	: res_t *icon2res(icon_t *ico)
+ * Input	:
+ *	ico	- The icon descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *icon2res(icon_t *ico)
+{
+	int restag;
+	res_t *res;
+	name_id_t name;
+
+	assert(ico != NULL);
+
+	res = new_res();
+	name.type = name_ord;
+	name.name.i_name = ico->id;
+	/* FIXME: Borland's rc compiler writes the default system's
+	 * language if none specified (0x406 for me that is). I believe
+	 * that this is a Borland bug (brc32 ver. 5.01), as the default
+	 * should be 0 (system default).
+	 */
+	restag = put_res_header(res, WRC_RT_ICON, NULL, &name, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, NULL);
+	put_raw_data(res, ico->data, 0);
+
+	SetResSize(res, restag);	/* Set ResourceSize */
+	if(win32)
+		put_pad(res);
+
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: bitmap2res
+ * Syntax	: res_t *bitmap2res(name_id_t *name, bitmap_t *bmp)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	bmp	- The bitmap descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *bitmap2res(name_id_t *name, bitmap_t *bmp)
+{
+	int restag;
+	res_t *res;
+	assert(name != NULL);
+	assert(bmp != NULL);
+
+	HEAPCHECK();
+	res = new_res();
+	HEAPCHECK();
+	restag = put_res_header(res, WRC_RT_BITMAP, NULL, name, bmp->memopt, NULL);
+	HEAPCHECK();
+	if(bmp->data->data[0] == 'B'
+	&& bmp->data->data[1] == 'M'
+	&& ((BITMAPFILEHEADER *)bmp->data->data)->bfSize == bmp->data->size
+	&& bmp->data->size >= sizeof(BITMAPFILEHEADER))
+	{
+		/* The File header is still attached, don't write it */
+		put_raw_data(res, bmp->data, sizeof(BITMAPFILEHEADER));
+	}
+	else
+	{
+		put_raw_data(res, bmp->data, 0);
+	}
+	HEAPCHECK();
+	/* Set ResourceSize */
+	SetResSize(res, restag);
+	HEAPCHECK();
+	if(win32)
+		put_pad(res);
+	HEAPCHECK();
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: font2res
+ * Syntax	: res_t *font2res(name_id_t *name, font_t *fnt)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	fnt	- The font descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *font2res(name_id_t *name, font_t *fnt)
+{
+	assert(name != NULL);
+	assert(fnt != NULL);
+	warning("Fonts not yet implemented");
+	return NULL;
+}
+
+/*
+ *****************************************************************************
+ * Function	: rcdata2res
+ * Syntax	: res_t *rcdata2res(name_id_t *name, rcdata_t *rdt)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	rdt	- The rcdata descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *rcdata2res(name_id_t *name, rcdata_t *rdt)
+{
+	int restag;
+	res_t *res;
+	assert(name != NULL);
+	assert(rdt != NULL);
+
+	res = new_res();
+	restag = put_res_header(res, WRC_RT_RCDATA, NULL, name, rdt->memopt, NULL);
+	put_raw_data(res, rdt->data, 0);
+	/* Set ResourceSize */
+	SetResSize(res, restag);
+	if(win32)
+		put_pad(res);
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: messagetable2res
+ * Syntax	: res_t *messagetable2res(name_id_t *name, messagetable_t *msg)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	msg	- The messagetable descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *messagetable2res(name_id_t *name, messagetable_t *msg)
+{
+	assert(name != NULL);
+	assert(msg != NULL);
+	warning("Messagetable not yet implemented");
+	return NULL;
+}
+
+/*
+ *****************************************************************************
+ * Function	: stringtable2res
+ * Syntax	: res_t *stringtable2res(stringtable_t *stt)
+ * Input	:
+ *	stt	- The stringtable descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *stringtable2res(stringtable_t *stt)
+{
+	res_t *res;
+	name_id_t name;
+	int i;
+	int restag;
+	DWORD lastsize = 0;
+
+	assert(stt != NULL);
+	res = new_res();
+
+	for(; stt; stt = stt->next)
+	{
+		if(!stt->nentries)
+		{
+			warning("Empty internal stringtable");
+			continue;
+		}
+		name.type = name_ord;
+		name.name.i_name = (stt->idbase >> 4) + 1;
+		restag = put_res_header(res, WRC_RT_STRING, NULL, &name, stt->memopt, win32 ? &(stt->lvc) : NULL);
+		for(i = 0; i < stt->nentries; i++)
+		{
+			if(stt->entries[i].str)
+			{
+				if(win32)
+					put_word(res, stt->entries[i].str->size);
+				else
+					put_byte(res, stt->entries[i].str->size);
+				put_string(res, stt->entries[i].str, win32 ? str_unicode : str_char, FALSE);
+			}
+			else
+			{
+				if(win32)
+					put_word(res, 0);
+				else
+					put_byte(res, 0);
+			}
+		}
+		/* Set ResourceSize */
+		SetResSize(res, restag - lastsize);
+		if(win32)
+			put_pad(res);
+		lastsize = res->size;
+	}
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: user2res
+ * Syntax	: res_t *user2res(name_id_t *name, user_t *usr)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	usr	- The userresource descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *user2res(name_id_t *name, user_t *usr)
+{
+	int restag;
+	res_t *res;
+	assert(name != NULL);
+	assert(usr != NULL);
+
+	res = new_res();
+	restag = put_res_header(res, 0, usr->type, name, usr->memopt, NULL);
+	put_raw_data(res, usr->data, 0);
+	/* Set ResourceSize */
+	SetResSize(res, restag);
+	if(win32)
+		put_pad(res);
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: versionblock2res
+ * Syntax	: void versionblock2res(res_t *res, ver_block_t *blk)
+ * Input	:
+ *	res	- Binary resource to write to
+ *	blk	- The version block to be written
+ * Output	:
+ * Description	:
+ * Remarks	: Self recursive
+ *****************************************************************************
+*/
+void versionblock2res(res_t *res, ver_block_t *blk, int level)
+{
+	ver_value_t *val;
+	int blksizetag;
+	int valblksizetag;
+	int valvalsizetag;
+	int tag;
+	int i;
+
+	blksizetag = res->size;
+	put_word(res, 0);	/* Will be overwritten later */
+	put_word(res, 0);
+	if(win32)
+		put_word(res, 0);	/* level ? */
+	put_string(res, blk->name, win32 ? str_unicode : str_char, TRUE);
+	put_pad(res);
+	for(val = blk->values; val; val = val->next)
+	{
+		if(val->type == val_str)
+		{
+			valblksizetag = res->size;
+			put_word(res, 0);	/* Will be overwritten later */
+			valvalsizetag = res->size;
+			put_word(res, 0);	/* Will be overwritten later */
+			if(win32)
+			{
+				put_word(res, level);
+			}
+			put_string(res, val->key, win32 ? str_unicode : str_char, TRUE);
+			put_pad(res);
+			tag = res->size;
+			put_string(res, val->value.str, win32 ? str_unicode : str_char, TRUE);
+			if(win32)
+				*(WORD *)&(res->data[valvalsizetag]) = (WORD)((res->size - tag) >> 1);
+			else
+				*(WORD *)&(res->data[valvalsizetag]) = (WORD)(res->size - tag);
+			*(WORD *)&(res->data[valblksizetag]) = (WORD)(res->size - valblksizetag);
+			put_pad(res);
+		}
+		else if(val->type == val_words)
+		{
+			valblksizetag = res->size;
+			put_word(res, 0);	/* Will be overwritten later */
+			valvalsizetag = res->size;
+			put_word(res, 0);	/* Will be overwritten later */
+			if(win32)
+			{
+				put_word(res, level);
+			}
+			put_string(res, val->key, win32 ? str_unicode : str_char, TRUE);
+			put_pad(res);
+			tag = res->size;
+			for(i = 0; i < val->value.words->nwords; i++)
+			{
+				put_word(res, val->value.words->words[i]);
+			}
+			*(WORD *)&(res->data[valvalsizetag]) = (WORD)(res->size - tag);
+			*(WORD *)&(res->data[valblksizetag]) = (WORD)(res->size - valblksizetag);
+			put_pad(res);
+		}
+		else if(val->type == val_block)
+		{
+			versionblock2res(res, val->value.block, level+1);
+		}
+		else
+		{
+			internal_error(__FILE__, __LINE__, "Invalid value indicator %d in VERSIONINFO", val->type);
+		}
+	}
+
+	/* Set blocksize */
+	*(WORD *)&(res->data[blksizetag]) = (WORD)(res->size - blksizetag);
+}
+
+/*
+ *****************************************************************************
+ * Function	: versioninfo2res
+ * Syntax	: res_t *versioninfo2res(name_id_t *name, versioninfo_t *ver)
+ * Input	:
+ *	name	- Name/ordinal of the resource
+ *	ver	- The versioninfo descriptor
+ * Output	: New .res format structure
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_t *versioninfo2res(name_id_t *name, versioninfo_t *ver)
+{
+	int restag;
+	int rootblocksizetag;
+	int valsizetag;
+	int tag;
+	res_t *res;
+	string_t vsvi;
+	ver_block_t *blk;
+
+	assert(name != NULL);
+	assert(ver != NULL);
+
+	vsvi.type = str_char;
+	vsvi.str.cstr = "VS_VERSION_INFO";
+	vsvi.size = 15; /* Excl. termination */
+
+	res = new_res();
+	restag = put_res_header(res, WRC_RT_VERSION, NULL, name, WRC_MO_MOVEABLE | WRC_MO_PURE, NULL);
+	rootblocksizetag = res->size;
+	put_word(res, 0);	/* BlockSize filled in later */
+	valsizetag = res->size;
+	put_word(res, 0);	/* ValueSize filled in later*/
+	if(win32)
+		put_word(res, 0);	/* Tree-level ? */
+	put_string(res, &vsvi, win32 ? str_unicode : str_char, TRUE);
+	if(win32)
+		put_pad(res);
+	tag = res->size;
+	put_dword(res, VS_FFI_SIGNATURE);
+	put_dword(res, VS_FFI_STRUCVERSION);
+	put_dword(res, (ver->filever_maj1 << 16) + (ver->filever_maj2 & 0xffff));
+	put_dword(res, (ver->filever_min1 << 16) + (ver->filever_min2 & 0xffff));
+	put_dword(res, (ver->prodver_maj1 << 16) + (ver->prodver_maj2 & 0xffff));
+	put_dword(res, (ver->prodver_min1 << 16) + (ver->prodver_min2 & 0xffff));
+	put_dword(res, ver->fileflagsmask);
+	put_dword(res, ver->fileflags);
+	put_dword(res, ver->fileos);
+	put_dword(res, ver->filetype);
+	put_dword(res, ver->filesubtype);
+	put_dword(res, 0);		/* FileDateMS */
+	put_dword(res, 0);		/* FileDateLS */
+	/* Set ValueSize */
+	*(WORD *)&(res->data[valsizetag]) = (WORD)(res->size - tag);
+	/* Descend into the blocks */
+	for(blk = ver->blocks; blk; blk = blk->next)
+		versionblock2res(res, blk, 0);
+	/* Set root block's size */
+	*(WORD *)&(res->data[rootblocksizetag]) = (WORD)(res->size - rootblocksizetag);
+
+	SetResSize(res, restag);
+	if(win32)
+		put_pad(res);
+
+	return res;
+}
+
+/*
+ *****************************************************************************
+ * Function	: prep_nid_for_label
+ * Syntax	: char *prep_nid_for_label(name_id_t *nid)
+ * Input	:
+ * Output	:
+ * Description	: Converts a resource name into the first 32 (or less)
+ *		  characters of the name with conversions.
+ * Remarks	:
+ *****************************************************************************
+*/
+#define MAXNAMELEN	32
+char *prep_nid_for_label(name_id_t *nid)
+{
+	static char buf[MAXNAMELEN+1];
+
+	assert(nid != NULL);
+
+	if(nid->type == name_str && nid->name.s_name->type == str_unicode)
+	{
+		short *sptr;
+		int i;
+		sptr = nid->name.s_name->str.wstr;
+		buf[0] = '\0';
+		for(i = 0; *sptr && i < MAXNAMELEN; i++)
+		{
+			if((unsigned)*sptr < 0x80 && isprint((char)*sptr))
+				buf[i] = *sptr++;
+			else
+				warning("Resourcename (str_unicode) contain unprintable characters or invalid translation, ignored");
+		}
+		buf[i] = '\0';
+	}
+	else if(nid->type == name_str && nid->name.s_name->type == str_char)
+	{
+		char *cptr;
+		int i;
+		cptr = nid->name.s_name->str.cstr;
+		buf[0] = '\0';
+		for(i = 0; *cptr && i < MAXNAMELEN; i++)
+		{
+			if((unsigned)*cptr < 0x80 && isprint(*cptr))
+				buf[i] = *cptr++;
+			else
+				warning("Resourcename (str_char) contain unprintable characters, ignored");
+		}
+		buf[i] = '\0';
+	}
+	else if(nid->type == name_ord)
+	{
+		sprintf(buf, "%u", nid->name.i_name);
+	}
+	else
+	{
+		internal_error(__FILE__, __LINE__, "Resource name_id with invalid type %d", nid->type);
+	}
+	return buf;
+}
+#undef MAXNAMELEN
+
+/*
+ *****************************************************************************
+ * Function	: make_c_name
+ * Syntax	: char *make_c_name(char *base, name_id_t *nid, language_t *lan)
+ * Input	:
+ * Output	:
+ * Description	: Converts a resource name into a valid c-identifier in the
+ *		  form "_base_nid".
+ * Remarks	:
+ *****************************************************************************
+*/
+char *make_c_name(char *base, name_id_t *nid, language_t *lan)
+{
+	int nlen;
+	char *buf;
+	char *ret;
+	char lanbuf[6];
+
+	sprintf(lanbuf, "%d", lan ? MAKELANGID(lan->id, lan->sub) : 0);
+	buf = prep_nid_for_label(nid);
+	nlen = strlen(buf) + strlen(lanbuf);
+	nlen += strlen(base) + 4; /* three time '_' and '\0' */
+	ret = (char *)xmalloc(nlen);
+	strcpy(ret, "_");
+	strcat(ret, base);
+	strcat(ret, "_");
+	strcat(ret, buf);
+	strcat(ret, "_");
+	strcat(ret, lanbuf);
+	return ret;
+}
+
+/*
+ *****************************************************************************
+ * Function	: get_c_typename
+ * Syntax	: char *get_c_typename(enum res_e type)
+ * Input	:
+ * Output	:
+ * Description	: Convert resource enum to char string to be used in c-name
+ *		  creation.
+ * Remarks	:
+ *****************************************************************************
+*/
+char *get_c_typename(enum res_e type)
+{
+	switch(type)
+	{
+	case res_acc:	return "Acc";
+	case res_bmp:	return "Bmp";
+	case res_cur:	return "Cur";
+	case res_curg:	return "CurGrp";
+	case res_dlg:
+	case res_dlgex:	return "Dlg";
+	case res_fnt:	return "Fnt";
+	case res_ico:	return "Ico";
+	case res_icog:	return "IcoGrp";
+	case res_men:
+	case res_menex:	return "Men";
+	case res_rdt:	return "RCDat";
+	case res_stt:	return "StrTab";
+	case res_usr:	return "Usr";
+	case res_msg:	return "MsgTab";
+	case res_ver:	return "VerInf";
+	default:	return "Oops";
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: resources2res
+ * Syntax	: void resources2res(resource_t *top)
+ * Input	:
+ *	top	- The resource-tree to convert
+ * Output	:
+ * Description	: Convert logical resource descriptors into binary data
+ * Remarks	:
+ *****************************************************************************
+*/
+void resources2res(resource_t *top)
+{
+	while(top)
+	{
+		switch(top->type)
+		{
+		case res_acc:
+			if(!top->binres)
+				top->binres = accelerator2res(top->name, top->res.acc);
+			break;
+		case res_bmp:
+			if(!top->binres)
+				top->binres = bitmap2res(top->name, top->res.bmp);
+			break;
+		case res_cur:
+			if(!top->binres)
+				top->binres = cursor2res(top->res.cur);
+			break;
+		case res_curg:
+			if(!top->binres)
+				top->binres = cursorgroup2res(top->name, top->res.curg);
+			break;
+		case res_dlg:
+			if(!top->binres)
+				top->binres = dialog2res(top->name, top->res.dlg);
+			break;
+		case res_dlgex:
+			if(!top->binres)
+				top->binres = dialogex2res(top->name, top->res.dlgex);
+			break;
+		case res_fnt:
+			if(!top->binres)
+				top->binres = font2res(top->name, top->res.fnt);
+			break;
+		case res_ico:
+			if(!top->binres)
+				top->binres = icon2res(top->res.ico);
+			break;
+		case res_icog:
+			if(!top->binres)
+				top->binres = icongroup2res(top->name, top->res.icog);
+			break;
+		case res_men:
+			if(!top->binres)
+				top->binres = menu2res(top->name, top->res.men);
+			break;
+		case res_menex:
+			if(!top->binres)
+				top->binres = menuex2res(top->name, top->res.menex);
+			break;
+		case res_rdt:
+			if(!top->binres)
+				top->binres = rcdata2res(top->name, top->res.rdt);
+			break;
+		case res_stt:
+			if(!top->binres)
+				top->binres = stringtable2res(top->res.stt);
+			break;
+		case res_usr:
+			if(!top->binres)
+				top->binres = user2res(top->name, top->res.usr);
+			break;
+		case res_msg:
+			if(!top->binres)
+				top->binres = messagetable2res(top->name, top->res.msg);
+			break;
+		case res_ver:
+			if(!top->binres)
+				top->binres = versioninfo2res(top->name, top->res.ver);
+			break;
+		default:
+			internal_error(__FILE__, __LINE__, "Unknown resource type encountered %d in binary res generation", top->type);
+		}
+		top->c_name = make_c_name(get_c_typename(top->type), top->name, top->lan);
+		top = top->next;
+	}
+}
+
diff --git a/tools/wrc/genres.h b/tools/wrc/genres.h
new file mode 100644
index 0000000..0f4d9d2
--- /dev/null
+++ b/tools/wrc/genres.h
@@ -0,0 +1,25 @@
+/*
+ * Generate resource prototypes
+ *
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ */
+
+#ifndef __WRC_GENRES_H
+#define __WRC_GENRES_H
+
+#ifndef __WRC_WRCTYPES_H
+#include "wrctypes.h"
+#endif
+
+res_t *new_res(void);
+res_t *grow_res(res_t *r, int add);
+void put_byte(res_t *res, unsigned c);
+void put_word(res_t *res, unsigned w);
+void put_dword(res_t *res, unsigned d);
+void resources2res(resource_t *top);
+char *get_c_typename(enum res_e type);
+char *make_c_name(char *base, name_id_t *nid, language_t *lan);
+char *prep_nid_for_label(name_id_t *nid);
+
+#endif
diff --git a/tools/wrc/newstruc.c b/tools/wrc/newstruc.c
new file mode 100644
index 0000000..6d33c4b
--- /dev/null
+++ b/tools/wrc/newstruc.c
@@ -0,0 +1,251 @@
+/*
+ * Create dynamic new structures of various types
+ * and some utils in that trend.
+ *
+ * Copyright 1998 Bertho A. Stultiens
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <config.h>
+#include "wrc.h"
+#include "newstruc.h"
+#include "utils.h"
+#include "parser.h"
+
+/* Generate new_* functions that have no parameters (NOTE: no ';') */
+__NEW_STRUCT_FUNC(dialog)
+__NEW_STRUCT_FUNC(dialogex)
+__NEW_STRUCT_FUNC(name_id)
+__NEW_STRUCT_FUNC(menu)
+__NEW_STRUCT_FUNC(menuex)
+__NEW_STRUCT_FUNC(menu_item)
+__NEW_STRUCT_FUNC(menuex_item)
+__NEW_STRUCT_FUNC(control)
+__NEW_STRUCT_FUNC(icon)
+__NEW_STRUCT_FUNC(cursor)
+__NEW_STRUCT_FUNC(versioninfo)
+__NEW_STRUCT_FUNC(ver_value)
+__NEW_STRUCT_FUNC(ver_block)
+__NEW_STRUCT_FUNC(stt_entry)
+__NEW_STRUCT_FUNC(accelerator)
+__NEW_STRUCT_FUNC(event)
+__NEW_STRUCT_FUNC(raw_data)
+__NEW_STRUCT_FUNC(lvc)
+__NEW_STRUCT_FUNC(res_count)
+__NEW_STRUCT_FUNC(string)
+
+/* New instances for all types of structures */
+/* Very inefficient (in size), but very functional :-]
+ * Especially for type-checking.
+ */
+resource_t *new_resource(enum res_e t, void *res, int memopt, language_t *lan)
+{
+	resource_t *r = (resource_t *)xmalloc(sizeof(resource_t));
+	r->type = t;
+	r->res.overlay = res;
+	r->memopt = memopt;
+	r->lan = lan;
+	return r;
+}
+
+version_t *new_version(DWORD v)
+{
+	version_t *vp = (version_t *)xmalloc(sizeof(version_t));
+	*vp = v;
+	return vp;
+}
+
+characts_t *new_characts(DWORD c)
+{
+	characts_t *cp = (characts_t *)xmalloc(sizeof(characts_t));
+	*cp = c;
+	return cp;
+}
+
+language_t *new_language(int id, int sub)
+{
+	language_t *lan = (language_t *)xmalloc(sizeof(language_t));
+	lan->id = id;
+	lan->sub = sub;
+	return lan;
+}
+
+language_t *dup_language(language_t *l)
+{
+	if(!l) return NULL;
+	return new_language(l->id, l->sub);
+}
+
+version_t *dup_version(version_t *v)
+{
+	if(!v) return NULL;
+	return new_version(*v);
+}
+
+characts_t *dup_characts(characts_t *c)
+{
+	if(!c) return NULL;
+	return new_characts(*c);
+}
+
+rcdata_t *new_rcdata(raw_data_t *rd, int *memopt)
+{
+	rcdata_t *rc = (rcdata_t *)xmalloc(sizeof(rcdata_t));
+	rc->data = rd;
+	if(memopt)
+	{
+		rc->memopt = *memopt;
+		free(memopt);
+	}
+	else
+		rc->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
+	return rc;
+}
+
+font_id_t *new_font_id(int size, string_t *face, int weight, int italic)
+{
+	font_id_t *fid = (font_id_t *)xmalloc(sizeof(font_id_t));
+	fid->name = face;
+	fid->size = size;
+	fid->weight = weight;
+	fid->italic = italic;
+	return fid;
+}
+
+user_t *new_user(name_id_t *type, raw_data_t *rd, int *memopt)
+{
+	user_t *usr = (user_t *)xmalloc(sizeof(user_t));
+	usr->data = rd;
+	if(memopt)
+	{
+		usr->memopt = *memopt;
+		free(memopt);
+	}
+	else
+		usr->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
+	usr->type = type;
+	return usr;
+}
+
+font_t *new_font(raw_data_t *rd, int *memopt)
+{
+	font_t *fnt = (font_t *)xmalloc(sizeof(font_t));
+	fnt->data = rd;
+	if(memopt)
+	{
+		fnt->memopt = *memopt;
+		free(memopt);
+	}
+	else
+		fnt->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
+	return fnt;
+}
+
+icon_group_t *new_icon_group(raw_data_t *rd, int *memopt)
+{
+	icon_group_t *icog = (icon_group_t *)xmalloc(sizeof(icon_group_t));
+	if(memopt)
+	{
+		icog->memopt = *memopt;
+		free(memopt);
+	}
+	else
+		icog->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
+	split_icons(rd, icog, &(icog->nicon));
+	free(rd->data);
+	free(rd);
+	return icog;
+}
+
+cursor_group_t *new_cursor_group(raw_data_t *rd, int *memopt)
+{
+	cursor_group_t *curg = (cursor_group_t *)xmalloc(sizeof(cursor_group_t));
+	if(memopt)
+	{
+		curg->memopt = *memopt;
+		free(memopt);
+	}
+	else
+		curg->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
+	split_cursors(rd, curg, &(curg->ncursor));
+	free(rd->data);
+	free(rd);
+	return curg;
+}
+
+bitmap_t *new_bitmap(raw_data_t *rd, int *memopt)
+{
+	bitmap_t *bmp = (bitmap_t *)xmalloc(sizeof(bitmap_t));
+	bmp->data = rd;
+	if(memopt)
+	{
+		bmp->memopt = *memopt;
+		free(memopt);
+	}
+	else
+		bmp->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
+	return bmp;
+}
+
+ver_words_t *new_ver_words(int i)
+{
+	ver_words_t *w = (ver_words_t *)xmalloc(sizeof(ver_words_t));
+	w->words = (WORD *)xmalloc(sizeof(WORD));
+	w->words[0] = (WORD)i;
+	w->nwords = 1;
+	return w;
+}
+
+ver_words_t *add_ver_words(ver_words_t *w, int i)
+{
+	w->words = (WORD *)xrealloc(w->words, (w->nwords+1) * sizeof(WORD));
+	w->words[w->nwords] = (WORD)i;
+	w->nwords++;
+	return w;
+}
+
+messagetable_t *new_messagetable(raw_data_t *rd)
+{
+	messagetable_t *msg = (messagetable_t *)xmalloc(sizeof(messagetable_t));
+	msg->data = rd;
+	return msg;
+}
+
+void copy_raw_data(raw_data_t *dst, raw_data_t *src, int offs, int len)
+{
+	assert(offs <= src->size);
+	assert(offs + len <= src->size);
+	if(!dst->data)
+	{
+		dst->data = (char *)xmalloc(len);
+		dst->size = 0;
+	}
+	else
+		dst->data = (char *)xrealloc(dst->data, dst->size + len);
+	/* dst->size holds the offset to copy to */
+	memcpy(dst->data + dst->size, src->data + offs, len);
+	dst->size += len;
+}
+
+int *new_int(int i)
+{
+	int *ip = (int *)xmalloc(sizeof(int));
+	*ip = i;
+	return ip;
+}
+
+stringtable_t *new_stringtable(lvc_t *lvc)
+{
+	stringtable_t *stt = (stringtable_t *)xmalloc(sizeof(stringtable_t));
+
+	if(lvc)
+		stt->lvc = *lvc;
+
+	return stt;
+}
+
+
diff --git a/tools/wrc/newstruc.h b/tools/wrc/newstruc.h
new file mode 100644
index 0000000..61d3907
--- /dev/null
+++ b/tools/wrc/newstruc.h
@@ -0,0 +1,66 @@
+/*
+ * Create dynamic new structures of various types
+ *
+ * Copyright 1998 Bertho A. Stultiens
+ *
+ */
+
+#ifndef __WRC_NEWSTRUC_H
+#define __WRC_NEWSTRUC_H
+
+#ifndef __WRC_WRCTYPES_H
+#include "wrctypes.h"
+#endif
+
+#define __NEW_STRUCT_FUNC(p)	\
+	p##_t *new_##p(void)\
+	{\
+		return (p##_t *)xmalloc(sizeof(p##_t));\
+	}
+
+#define __NEW_STRUCT_PROTO(p)	p##_t *new_##p(void)
+
+__NEW_STRUCT_PROTO(dialog);
+__NEW_STRUCT_PROTO(dialogex);
+__NEW_STRUCT_PROTO(name_id);
+__NEW_STRUCT_PROTO(menu);
+__NEW_STRUCT_PROTO(menuex);
+__NEW_STRUCT_PROTO(menu_item);
+__NEW_STRUCT_PROTO(menuex_item);
+__NEW_STRUCT_PROTO(control);
+__NEW_STRUCT_PROTO(icon);
+__NEW_STRUCT_PROTO(cursor);
+__NEW_STRUCT_PROTO(versioninfo);
+__NEW_STRUCT_PROTO(ver_value);
+__NEW_STRUCT_PROTO(ver_block);
+__NEW_STRUCT_PROTO(stt_entry);
+__NEW_STRUCT_PROTO(accelerator);
+__NEW_STRUCT_PROTO(event);
+__NEW_STRUCT_PROTO(raw_data);
+__NEW_STRUCT_PROTO(lvc);
+__NEW_STRUCT_PROTO(res_count);
+__NEW_STRUCT_PROTO(string);
+
+resource_t *new_resource(enum res_e t, void *res, int memopt, language_t *lan);
+version_t *new_version(DWORD v);
+characts_t *new_characts(DWORD c);
+language_t *new_language(int id, int sub);
+language_t *dup_language(language_t *l);
+version_t *dup_version(version_t *v);
+characts_t *dup_characts(characts_t *c);
+rcdata_t *new_rcdata(raw_data_t *rd, int *memopt);
+font_id_t *new_font_id(int size, string_t *face, int weight, int italic);
+user_t *new_user(name_id_t *type, raw_data_t *rd, int *memopt);
+font_t *new_font(raw_data_t *rd, int *memopt);
+icon_group_t *new_icon_group(raw_data_t *rd, int *memopt);
+cursor_group_t *new_cursor_group(raw_data_t *rd, int *memopt);
+bitmap_t *new_bitmap(raw_data_t *rd, int *memopt);
+ver_words_t *new_ver_words(int i);
+ver_words_t *add_ver_words(ver_words_t *w, int i);
+messagetable_t *new_messagetable(raw_data_t *rd);
+void copy_raw_data(raw_data_t *dst, raw_data_t *src, int offs, int len);
+int *new_int(int i);
+stringtable_t *new_stringtable(lvc_t *lvc);
+
+#endif
+
diff --git a/tools/wrc/parser.h b/tools/wrc/parser.h
new file mode 100644
index 0000000..a038371
--- /dev/null
+++ b/tools/wrc/parser.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ * Shared things between parser.l and parser.y and some others
+ */
+
+#ifndef __WRC_PARSER_H
+#define __WRC_PARSER_H
+
+/* From parser.y */
+extern int yydebug;
+extern int indialog;		/* Set when parsing dialogs */
+extern int want_rscname;	/* Set when a resource's name is required */
+
+int yyparse(void);
+void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico);
+void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur);
+
+/* From parser.l */
+extern FILE *yyin;
+extern int line_number;
+
+int yylex(void);
+void set_yywf(void);
+void set_pp_ignore(int state);
+void push_to(int start);
+void pop_start(void);
+void strip_til_semicolon(void);
+void strip_til_parenthesis(void);
+
+#endif
+
diff --git a/tools/wrc/parser.l b/tools/wrc/parser.l
new file mode 100644
index 0000000..7b411d8
--- /dev/null
+++ b/tools/wrc/parser.l
@@ -0,0 +1,862 @@
+/* -*-C-*-
+ *
+ * Copyright 1994 Martin von Loewis
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ * 19-May-1998 BS	- Started to build a preprocessor.
+ *			- Changed keyword processing completely to
+ *			  table-lookups.
+ *
+ * 20-Apr-1998 BS	- Added ';' comment stripping
+ *
+ * 17-Apr-1998 BS	- Made the win32 keywords optional when compiling in
+ *			  16bit mode
+ *
+ * 15-Apr-1998 BS	- Changed string handling to include escapes
+ *			- Added unicode string handling (no codepage
+ *			  translation though).
+ *			- 'Borrowed' the main idea of string scanning from
+ *			  the flex manual pages.
+ *			- Added conditional handling of scanning depending
+ *			  on the state of the parser. This was mainly required
+ *			  to distinguish a file to load or raw data that
+ *			  follows. MS's definition of filenames is rather
+ *			  complex... It can be unquoted or double quoted. If
+ *			  double quoted, then the '\\' char is not automatically
+ *			  escaped according to Borland's rc compiler, but it
+ *			  accepts both "\\path\\file.rc" and "\path\file.rc".
+ *			  This makes life very hard! I go for the escaped
+ *			  version, as this seems to be the documented way...
+ *			- Single quoted strings are now parsed and converted
+ *			  here.
+ *			- Added comment stripping. The implementation is
+ *			  'borrowed' from the flex manpages.
+ *			- Rebuild string processing so that it may contain
+ *			  escaped '\0'.
+ */
+
+/* Exclusive rules when looking for a filename */
+%x yywf
+/* Exclusive string handling */
+%x yystr
+/* Exclusive unicode string handling */
+%x yylstr
+/* Exclusive rcdata single quoted data handling */
+%x yyrcd
+/* Exclusive comment eating... */
+%x comment
+/* Preprocessor exclusives */
+%x pp_incl
+%x pp_def
+%x pp_undef
+%x pp_if
+%x pp_ifdef
+%x pp_ifndef
+%x pp_elif
+%x pp_else
+%x pp_endif
+%x pp_error
+/* Set when accumulating #define's expansion text */
+%x pp_def_s
+/* Set when processing function type defines */
+%x pp_ignore
+/* Set when need to strip to eol */
+%x pp_ignore_eol
+/* Set when handling a false #if case */
+%x pp_false
+/* Set when stripping c-junk */
+%x pp_strips
+%x pp_stripp
+%x pp_stripp_final
+
+/*%option stack*/
+%option never-interactive
+/*%option noyywrap */
+/* Some shortcut definitions */
+ws	[ \f\t\r]
+cident	[a-zA-Z_][0-9a-zA-Z_]*
+
+%{
+
+/*#define LEX_DEBUG*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <config.h>
+#include "wrc.h"
+#include "utils.h"
+#include "preproc.h"
+#include "parser.h"
+#include "newstruc.h"
+
+#include "y.tab.h"
+
+#define YY_USE_PROTOS
+#define YY_NO_UNPUT
+
+raw_data_t *new_raw_data(void);
+
+void addcchar(char c);
+void addwchar(short s);
+string_t *get_buffered_cstring(void);
+string_t *get_buffered_wstring(void);
+string_t *make_string(char *s);
+
+int line_number = 1;
+static char cbuffer[1024];	/* Buffers for string collection */
+static int cbufidx;
+static short wbuffer[1024];
+static int wbufidx;
+static int want_nl = 0;		/* Set when newline needs to go to parser */
+static int want_ident = 0;	/* Set is #ifdef, #ifndef or defined is seen */
+static int stripslevel = 0;	/* Count {} during pp_strips mode */
+static int stripplevel = 0;	/* Count () during pp_strips mode */
+static char *substtext = NULL;	/* Holds the substition text while getting a define */
+static int cjunk_tagline;	/* Where did we start stripping (helps error tracking) */
+
+#ifdef YY_USE_STACK
+void push_to(int start)	{ yy_push_state(start); }
+void pop_start(void)	{ yy_pop_state(start); }
+#else
+#define MAXSTARTSTACK	32
+static int startstack[MAXSTARTSTACK];
+static int startstackidx = 0;
+
+void push_to(int start)
+{
+	if(yydebug)
+		printf("push_to(%d): %d -> %d\n", line_number, YY_START, start);
+	if(startstackidx >= MAXSTARTSTACK-1)
+		internal_error(__FILE__, __LINE__, "Start condition stack overflow");
+	startstack[startstackidx++] = YY_START;
+	BEGIN(start);
+}
+
+void pop_start(void)
+{
+	if(yydebug)
+		printf("pop_start(%d): %d <- %d\n", line_number, startstack[startstackidx-1], YY_START);
+	if(startstackidx <= 0)
+		internal_error(__FILE__, __LINE__, "Start condition stack underflow");
+	--startstackidx;
+	BEGIN(startstack[startstackidx]);
+}
+#endif
+
+
+struct bufferstackentry {
+	YY_BUFFER_STATE	bufferstate;	/* Buffer to switch back to */
+	struct pp_entry	*define;	/* Points to expanding define
+					   or NULL if handling includes
+					 */
+	int line_number;		/* Line that we were handling */
+	char *filename;			/* Filename that we were handling */
+};
+
+#define MAXBUFFERSTACK 128
+static struct bufferstackentry bufferstack[MAXBUFFERSTACK];
+static int bufferstackidx = 0;
+
+void push_buffer(YY_BUFFER_STATE buf, struct pp_entry *ppp, char *filename)
+{
+	if(yydebug)
+		printf("push_buffer: %p %p %p\n", buf, ppp, filename);
+	if(bufferstackidx >= MAXBUFFERSTACK-1)
+		internal_error(__FILE__, __LINE__, "Buffer stack overflow");
+	memset(&bufferstack[bufferstackidx], 0, sizeof(bufferstack[0]));
+	bufferstack[bufferstackidx].bufferstate = buf;
+	bufferstack[bufferstackidx].define = ppp;
+	if(ppp)
+		ppp->expanding = 1;
+	else if(filename)
+	{
+		/* These will track the yyerror to the correct file and line */
+		bufferstack[bufferstackidx].line_number = line_number;
+		line_number = 1;
+		bufferstack[bufferstackidx].filename = input_name;
+		input_name = filename;
+	}
+	else
+		internal_error(__FILE__, __LINE__, "Pushing buffer without knowing where to go to");
+	bufferstackidx++;
+}
+
+YY_BUFFER_STATE pop_buffer(void)
+{
+	if(bufferstackidx <= 0)
+		return (YY_BUFFER_STATE)0;
+	bufferstackidx--;
+	if(bufferstack[bufferstackidx].define)
+		bufferstack[bufferstackidx].define->expanding = 0;
+	else
+	{
+		line_number = bufferstack[bufferstackidx].line_number;
+		input_name = bufferstack[bufferstackidx].filename;
+		fclose(yyin);
+	}
+	if(yydebug)
+		printf("pop_buffer: %p %p (%d) %p\n",
+			bufferstack[bufferstackidx].bufferstate,
+			bufferstack[bufferstackidx].define,
+			bufferstack[bufferstackidx].line_number,
+			bufferstack[bufferstackidx].filename);
+	yy_switch_to_buffer(bufferstack[bufferstackidx].bufferstate);
+	return bufferstack[bufferstackidx].bufferstate;
+}
+
+void do_include(char *name, int namelen)
+{
+	char *cpy = (char *)xmalloc(namelen);
+	strcpy(cpy, name+1);	/* strip leading " or < */
+	cpy[namelen-2] = '\0';	/* strip trailing " or > */
+	if((yyin = open_include(cpy, name[0] == '"')) == NULL)
+		yyerror("Unable to open include file %s", cpy);
+	push_buffer(YY_CURRENT_BUFFER, NULL, cpy);
+	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+}
+
+
+struct keyword {
+	char	*keyword;
+	int	token;
+	int	isextension;
+	int	needcase;
+	int	alwayskeyword;
+};
+
+static struct keyword keywords[] = {
+	{ "ACCELERATORS", ACCELERATORS, 0, 0, 0},
+	{ "ALT", ALT, 0, 0, 0},
+	{ "ASCII", ASCII, 0, 0, 0},
+	{ "AUTO3STATE", AUTO3STATE, 1, 0, 0},
+	{ "AUTOCHECKBOX", AUTOCHECKBOX, 1, 0, 0},
+	{ "AUTORADIOBUTTON", AUTORADIOBUTTON, 1, 0, 0},
+	{ "BEGIN", tBEGIN, 0, 0, 1},
+	{ "BITMAP", tBITMAP, 0, 0, 0},
+	{ "BLOCK", BLOCK, 0, 0, 1},
+	{ "CAPTION", CAPTION, 0, 0, 0},
+	{ "CHARACTERISTICS", CHARACTERISTICS, 1, 0, 0},
+	{ "CHECKBOX", CHECKBOX, 0, 0, 0},
+	{ "CHECKED", CHECKED, 0, 0, 0},
+	{ "CLASS", CLASS, 0, 0, 0},
+	{ "COMBOBOX", COMBOBOX, 0, 0, 0},
+	{ "CONTROL", CONTROL, 0, 0, 0},
+	{ "CTEXT", CTEXT, 0, 0, 0},
+	{ "CURSOR", CURSOR, 0, 0, 0},
+	{ "defined", tDEFINED, 0, 1, 1},
+	{ "DEFPUSHBUTTON", DEFPUSHBUTTON, 0, 0, 1},
+	{ "DIALOG", DIALOG, 0, 0, 0},
+	{ "DIALOGEX", DIALOGEX, 1, 0, 0},
+	{ "DISCARDABLE", DISCARDABLE, 0, 0, 0},
+	{ "EDITTEXT", EDITTEXT, 0, 0, 0},
+	{ "END", tEND, 0, 0, 1},
+	{ "EXSTYLE", EXSTYLE, 0, 0, 0},
+	{ "extern", tEXTERN, 0, 1, 1},
+	{ "FILEFLAGS", FILEFLAGS, 0, 0, 0},
+	{ "FILEFLAGSMASK", FILEFLAGSMASK, 0, 0, 0},
+	{ "FILEOS", FILEOS, 0, 0, 0},
+	{ "FILESUBTYPE", FILESUBTYPE, 0, 0, 0},
+	{ "FILETYPE", FILETYPE, 0, 0, 0},
+	{ "FILEVERSION", FILEVERSION, 0, 0, 0},
+	{ "FIXED", tFIXED, 0, 0, 0},
+	{ "FONT", FONT, 0, 0, 0},
+	{ "GRAYED", GRAYED, 0, 0, 0},
+	{ "GROUPBOX", GROUPBOX, 0, 0, 0},
+	{ "HELP", HELP, 0, 0, 0},
+	{ "ICON", ICON, 0, 0, 0},
+	{ "IMPURE", IMPURE, 0, 0, 0},
+	{ "INACTIVE", INACTIVE, 0, 0, 0},
+	{ "LANGUAGE", LANGUAGE, 1, 0, 1},
+	{ "LISTBOX", LISTBOX, 0, 0, 0},
+	{ "LOADONCALL", LOADONCALL, 0, 0, 0},
+	{ "LTEXT", LTEXT, 0, 0, 0},
+	{ "MENU", MENU, 0, 0, 0},
+	{ "MENUBARBREAK", MENUBARBREAK, 0, 0, 0},
+	{ "MENUBREAK", MENUBREAK, 0, 0, 0},
+	{ "MENUEX", MENUEX, 1, 0, 0},
+	{ "MENUITEM", MENUITEM, 0, 0, 0},
+	{ "MESSAGETABLE", MESSAGETABLE, 1, 0, 0},
+	{ "MOVEABLE", MOVEABLE, 0, 0, 0},
+	{ "NOINVERT", NOINVERT, 0, 0, 0},
+	{ "NOT", NOT, 0, 0, 0},
+	{ "POPUP", POPUP, 0, 0, 0},
+	{ "PRELOAD", PRELOAD, 0, 0, 0},
+	{ "PRODUCTVERSION", PRODUCTVERSION, 0, 0, 0},
+	{ "PURE", tPURE, 0, 0, 0},
+	{ "PUSHBUTTON", PUSHBUTTON, 0, 0, 0},
+	{ "RADIOBUTTON", RADIOBUTTON, 0, 0, 0},
+	{ "RCDATA", RCDATA, 0, 0, 0},
+	{ "RTEXT", RTEXT, 0, 0, 0},
+	{ "SCROLLBAR", SCROLLBAR, 0, 0, 0},
+	{ "SEPARATOR", SEPARATOR, 0, 0, 0},
+	{ "SHIFT", SHIFT, 0, 0, 0},
+	{ "STATE3", STATE3, 1, 0, 0},
+	{ "STRING", tSTRING, 0, 0, 0},
+	{ "STRINGTABLE", STRINGTABLE, 0, 0, 1},
+	{ "STYLE", STYLE, 0, 0, 0},
+	{ "typedef", tTYPEDEF, 0, 1, 1},
+	{ "VALUE", VALUE, 0, 0, 0},
+	{ "VERSION", VERSION, 1, 0, 0},
+	{ "VERSIONINFO", VERSIONINFO, 0, 0, 0},
+	{ "VIRTKEY", VIRTKEY, 0, 0, 0}
+};
+
+#define NKEYWORDS	(sizeof(keywords)/sizeof(keywords[0]))
+#define KWP(p)		((struct keyword *)(p))
+int kw_cmp_func(const void *s1, const void *s2)
+{
+	int ret;
+	ret = stricmp(KWP(s1)->keyword, KWP(s2)->keyword);
+	if(!ret && (KWP(s1)->needcase || KWP(s2)->needcase))
+		return strcmp(KWP(s1)->keyword, KWP(s2)->keyword);
+	else
+		return ret;
+}
+
+#define KW_BSEARCH
+#define DO_SORT
+struct keyword *iskeyword(char *kw)
+{
+	struct keyword *kwp;
+	struct keyword key;
+	key.keyword = kw;
+	key.needcase = 0;
+#ifdef DO_SORT
+	{
+		/* Make sure that it is sorted for bsearsh */
+		static int sorted = 0;
+		if(!sorted)
+		{
+			qsort(keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
+			sorted = 1;
+		}
+	}
+#endif
+#ifdef KW_BSEARCH
+	kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
+#else
+	{
+		int i;
+		for(i = 0; i < NKEYWORDS; i++)
+		{
+			if(!kw_cmp_func(&key, &keywords[i]))
+				break;
+		}
+		if(i < NKEYWORDS)
+			kwp = &keywords[i];
+		else
+			kwp = NULL;
+	}
+#endif
+
+#ifdef LEX_DEBUG
+	if(kwp && !strcmp(kwp->keyword, "LANGUAGE"))
+		printf("Got Language\n");
+#endif
+	if(kwp == NULL || (kwp->isextension && !extensions))
+		return NULL;
+	else
+		return kwp;
+}
+
+void add_to_substtext(char *text, int len)
+{
+	if(!substtext)
+	{
+		substtext = xstrdup(text);
+	}
+	else
+	{
+		substtext = (char *)xrealloc(substtext, strlen(substtext)+len+1);
+		strcat(substtext, text);
+	}
+}
+
+%}
+
+%%
+	/* #include handling */
+^{ws}*#{ws}*include{ws}*	push_to(pp_incl);
+<pp_incl>\<[^\n\>]+\>		do_include(yytext, yyleng); pop_start();
+<pp_incl>\"[^\n\>]+\"		do_include(yytext, yyleng); pop_start();
+<pp_incl>.		yyerror("Malformed #include");
+
+	/* #define handling */
+^{ws}*#{ws}*define{ws}*	push_to(pp_def);
+<pp_def>{cident}	{
+				set_define(yytext);
+				push_to(pp_def_s);
+			}
+<pp_def>{cident}\(	push_to(pp_ignore); /* Ignore function-like defines for now*/
+<pp_def>.		yyerror("Malformed #define");
+
+<pp_ignore,pp_def_s>[^\/\\\n]*	{
+			if(YY_START == pp_def_s)
+				add_to_substtext(yytext, yyleng);
+		}
+<pp_ignore,pp_def_s>\/[^\/\*][^\/\\\n]*	{ /* Comment is handled in normal handling */
+			if(YY_START == pp_def_s)
+				add_to_substtext(yytext, yyleng);
+		}
+<pp_ignore,pp_def_s>\\{ws}*\n	line_number++;	/* Line continuation */
+<pp_ignore,pp_def_s>\n		{
+			if(YY_START == pp_def_s)
+			{
+				add_define(substtext ? substtext : "");
+				free(substtext);
+				substtext = NULL;
+			}
+			line_number++;
+			pop_start();
+			pop_start();
+		}
+
+	/* #undef handling */
+^{ws}*#{ws}*undef{ws}*	push_to(pp_undef);
+<pp_undef>{cident}	{
+				del_define(yytext);
+				pop_start();
+				/*push_to(pp_ignore);*/
+			}
+
+	/* Conditional handling */
+<INITIAL,pp_strips,pp_stripp,pp_false>^{ws}*#{ws}*if{ws}*	{
+			if(YY_START == pp_false)
+			{
+				if(yydebug)
+					printf("(%d)#if ignored\n", line_number);
+				push_if(0, 0, 1);
+				push_to(pp_ignore_eol);
+			}
+			else
+			{
+				push_to(INITIAL);
+				want_nl = 1;
+				return tIF;
+			}
+		}
+<INITIAL,pp_strips,pp_stripp,pp_false>^{ws}*#{ws}*ifdef{ws}*	{
+			if(YY_START == pp_false)
+			{
+				if(yydebug)
+					printf("(%d)#ifdef ignored\n", line_number);
+				push_if(0, 0, 1);
+				push_to(pp_ignore_eol);
+			}
+			else
+			{
+				push_to(INITIAL);
+				want_nl = 1;
+				want_ident = 1;
+				return tIFDEF;
+			}
+		}
+<INITIAL,pp_strips,pp_stripp,pp_false>^{ws}*#{ws}*ifndef{ws}*	{
+			if(YY_START == pp_false)
+			{
+				if(yydebug)
+					printf("(%d)#ifndef ignored\n", line_number);
+				push_if(0, 0, 1);
+				push_to(pp_ignore_eol);
+			}
+			else
+			{
+				push_to(INITIAL);
+				want_nl = 1;
+				want_ident = 1;
+				return tIFNDEF;
+			}
+		}
+<INITIAL,pp_strips,pp_stripp,pp_false>^{ws}*#{ws}*elif{ws}*	{
+			if(!isnevertrue_if())
+			{
+				push_to(INITIAL);
+				want_nl = 1;
+				return tELIF;
+			}
+			else if(YY_START == pp_false)
+				push_to(pp_ignore_eol);
+			if(yydebug)
+				printf("(%d)#elif ignored\n", line_number);
+		}
+<INITIAL,pp_strips,pp_stripp,pp_false>^{ws}*#{ws}*else{ws}*	{
+			if(!isnevertrue_if())
+			{
+				push_to(INITIAL);
+				want_nl = 1;
+				return tELSE;
+			}
+			if(yydebug)
+				printf("(%d)#else ignored\n", line_number);
+		}
+<INITIAL,pp_strips,pp_stripp,pp_false>^{ws}*#{ws}*endif{ws}*	{
+			if(!isnevertrue_if())
+			{
+				want_nl = 1;
+				return tENDIF;
+			}
+			else
+			{
+				if(yydebug)
+					printf("(%d)#endif ignored\n", line_number);
+				pop_if();
+			}
+		}
+
+	/* The error directive */
+^{ws}*#{ws}*error{ws}*	push_to(pp_error);
+<pp_error>[^\n]*	yyerror("Error directive: %s", yytext);
+
+	/* preprocessor junk */
+^{ws}*#{ws}*pragma[^\n]*	;	/* Ignore #pragma */
+^{ws}*#{ws}*line[^\n]*		;	/* Ignore #line */
+ /* We'll get an error on malformed #xxx statements
+  * by not recognising '#' at all. This helps tracking
+  * preprocessor errors.
+  */
+ /*^{ws}*#{ws}*			;	 Ignore # */
+
+<pp_strips>\{		stripslevel++;
+<pp_strips>\}		stripslevel--;
+<pp_strips>;		if(!stripslevel) pop_start();
+<pp_strips>[^\{\};\n#]*	; /* Ignore rest */
+
+<pp_stripp>\(		stripplevel++;
+<pp_stripp>\)		{
+				stripplevel--;
+				if(!stripplevel)
+				{
+					pop_start();
+					push_to(pp_stripp_final);
+				}
+			}
+<pp_stripp>[^\(\);\n#]*	; /* Ignore rest */
+
+<pp_stripp_final>{ws}*	; /* Ignore */
+<pp_stripp_final>;	pop_start(); /* Kill the semicolon */
+<pp_stripp_final>\n	line_number++; pop_start();
+<pp_stripp_final>.	yyless(0); pop_start();
+
+<pp_false>.		;	/* Ignore everything except #xxx during false #if state */
+
+<pp_ignore_eol>[^\n]*	pop_start();
+
+ /* These are special cases due to filename scanning */
+<yywf>[Dd][Ii][Ss][Cc][Aa][Rr][Dd][Aa][Bb][Ll][Ee]	return DISCARDABLE;
+<yywf>[Ff][Ii][Xx][Ee][Dd]				return tFIXED;
+<yywf>[Ii][Mm][Pp][Uu][Rr][Ee]				return IMPURE;
+<yywf>[Mm][Oo][Vv][Ee][Aa][Bb][Ll][Ee]			return MOVEABLE;
+<yywf>[Ll][Oo][Aa][Dd][Oo][Nn][Cc][Aa][Ll][Ll]		return LOADONCALL;
+<yywf>[Pp][Rr][Ee][Ll][Oo][Aa][Dd]			return PRELOAD;
+<yywf>[Pp][Uu][Rr][Ee]					return tPURE;
+
+\{			return tBEGIN;
+\}			return tEND;
+
+[0-9]+[lL]?		{ yylval.num = atoi(yytext); return NUMBER; }
+0[xX][0-9A-Fa-f]+[lL]?	{ yylval.num = strtoul(yytext,0,16); return NUMBER; }
+0[oO][0-7]+		{ yylval.num = strtoul(yytext+2,0,8); return NUMBER; }
+[A-Za-z_0-9]+		{
+				struct keyword *token;
+				struct pp_entry *ppp;
+
+				want_rscname = 0;
+				
+				if(want_ident)
+				{
+					/* Prevent preprocessor subst */
+					want_ident = 0;
+					yylval.str = make_string(yytext);
+				#ifdef LEX_DEBUG
+					printf("want IDENT (%s, %d): <%s>\n", input_name, line_number, yytext);
+				#endif
+					return IDENT;
+				}
+				else if((ppp = pp_lookup(yytext)) != NULL)
+				{
+					/* Do preprocessor substitution,
+					 * but expand only if macro is not
+					 * already expanding.
+					 */
+					if(!ppp->expanding)
+					{
+				#ifdef LEX_DEBUG
+						printf("expand IDENT (%s, %d): <%s>\n", input_name, line_number, yytext);
+				#endif
+						push_buffer(YY_CURRENT_BUFFER, ppp, NULL);
+						yy_scan_string(ppp->subst);
+					}
+				}
+				else if((token = iskeyword(yytext)) != NULL
+				  && !(!token->alwayskeyword && want_rscname))
+				{
+					switch(token->token)
+					{
+					case tDEFINED:
+						want_ident = 1;
+						break;
+					/*case RCDATA:*/
+					case CURSOR:
+					case tBITMAP:
+					case MESSAGETABLE:
+						push_to(yywf);
+						break;
+					case FONT:
+					case ICON:
+						if(!indialog)
+							push_to(yywf);
+						break;
+					case DIALOG:
+					case DIALOGEX:
+						indialog = 1;
+						break;
+					}
+					return token->token;
+				}
+				else
+				{
+					yylval.str = make_string(yytext);
+				#ifdef LEX_DEBUG
+					printf("%s IDENT (%s, %d): <%s>\n",
+						want_rscname ? "rscname" : "just",
+						input_name,
+						line_number,
+						yytext);
+				#endif
+					return IDENT;
+				}
+			}
+\|\|			return LOGOR;
+\&\&			return LOGAND;
+\=\=			return EQ;
+\!\=			return NE;
+\<\=			return LTE;
+\>\=			return GTE;
+
+<yywf>[^ \f\t\r\n]*	{ pop_start(); yylval.str = make_string(yytext); return FILENAME; }
+<yywf>\"[^\"]*\"	{ pop_start(); yylval.str = make_string(yytext); return FILENAME; }
+
+L\"			{
+				push_to(yylstr);
+				wbufidx = 0;
+				if(!win32)
+					yywarning("16bit resource contains unicode strings\n");
+			}
+<yylstr>\"		{
+				pop_start();
+				yylval.str = get_buffered_wstring();
+				return tSTRING;
+			}
+<yylstr>\n		yyerror("Unterminated string");
+<yylstr>\\[0-7]{1,6}	{ /* octal escape sequence */
+				int result;
+				result = strtol(yytext+1, 0, 8);
+				if ( result > 0xffff )
+					yyerror("Character constant out of range");
+				addwchar((short)result);
+			}
+<yylstr>\\x[0-9a-fA-F]{4} {  /* hex escape sequence */
+				int result;
+				result = strtol(yytext+2, 0, 16);
+				addwchar((short)result);
+			}
+<yylstr>\\[0-9]+	yyerror("Bad escape secuence");
+<yylstr>\\a		addwchar('\a');
+<yylstr>\\b		addwchar('\b');
+<yylstr>\\f		addwchar('\f');
+<yylstr>\\n		addwchar('\n');
+<yylstr>\\r		addwchar('\r');
+<yylstr>\\t		addwchar('\t');
+<yylstr>\\v		addwchar('\v');
+<yylstr>\\(.|\n)	addwchar(yytext[1]);
+<yylstr>[^\\\n\"]+	{
+				char *yptr = yytext;
+				while(*yptr)	/* FIXME: codepage translation */
+					addwchar(*yptr++ & 0xff);
+			}
+
+\"			{
+				push_to(yystr);
+				cbufidx = 0;
+			}
+<yystr>\"		{
+				pop_start();
+				yylval.str = get_buffered_cstring();
+				return tSTRING;
+			}
+<yystr>\n		yyerror("Unterminated string");
+<yystr>\\[0-7]{1,3}	{ /* octal escape sequence */
+				int result;
+				result = strtol(yytext+1, 0, 8);
+				if ( result > 0xff )
+					yyerror("Character constant out of range");
+				addcchar((char)result);
+			}
+<yystr>\\x[0-9a-fA-F]{2} {  /* hex escape sequence */
+				int result;
+				result = strtol(yytext+2, 0, 16);
+				addcchar((char)result);
+			}
+<yystr>\\[0-9]+		yyerror("Bad escape secuence");
+<yystr>\\a		addcchar('\a');
+<yystr>\\b		addcchar('\b');
+<yystr>\\f		addcchar('\f');
+<yystr>\\n		addcchar('\n');
+<yystr>\\r		addcchar('\r');
+<yystr>\\t		addcchar('\t');
+<yystr>\\v		addcchar('\v');
+<yystr>\\(.|\n)		addcchar(yytext[1]);
+<yystr>[^\\\n\"]+	{
+				char *yptr = yytext;
+				while(*yptr)
+					addcchar(*yptr++);
+			}
+
+
+
+\'			{
+				push_to(yyrcd);
+				cbufidx = 0;
+			}
+<yyrcd>\'		{
+				pop_start();
+				yylval.raw = new_raw_data();
+				yylval.raw->size = cbufidx;
+				yylval.raw->data = xmalloc(yylval.raw->size);
+				memcpy(yylval.raw->data, cbuffer, yylval.raw->size);
+				return RAWDATA;
+			}
+<yyrcd>[0-9a-fA-F]{2}	{
+				int result;
+				result = strtol(yytext, 0, 16);
+				addcchar((char)result);
+			}
+<yyrcd>{ws}+		;	/* Ignore space */
+<yyrcd>.		yyerror("Malformed data-line");
+
+<INITIAL,pp_ignore,pp_def_s>"/*"	push_to(comment);	/* Eat comment */
+<comment>[^*\n]*	;
+<comment>"*"+[^*/\n]*	;
+<comment>\n		line_number++;
+<comment>"*"+"/"	pop_start();
+
+;[^\n]*			; /* Eat comment */
+<INITIAL,pp_ignore,pp_def_s>"//"[^\n]*		; /* Eat comment */
+
+<INITIAL,yywf,pp_false,pp_strips,pp_stripp>\n	{
+				if(YY_START == yywf)
+					pop_start();
+				line_number++;
+				if(want_nl)
+				{
+					want_nl = 0;
+					return tNL;
+				}
+			}
+<INITIAL,yywf>{ws}+	;	/* Eat whitespace */
+
+<INITIAL>.		return yytext[0];
+<<EOF>>			{
+				YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+				if(!pop_buffer())
+					if(YY_START == pp_strips || YY_START == pp_stripp || YY_START == pp_stripp_final)
+						yyerror("Unexpected end of file during c-junk scanning (started at %d)", cjunk_tagline);
+					else
+						yyterminate();
+				yy_delete_buffer(b);
+			}
+%%
+
+#ifndef yywrap
+int yywrap(void)
+{
+//	if(bufferstackidx > 0)
+//	{
+//		return 0;
+//	}
+	return 1;
+}
+#endif
+
+/* These dup functions copy the enclosed '\0' from
+ * the resource string.
+ */
+void addcchar(char c)
+{
+	if(cbufidx >= sizeof(cbuffer))
+		internal_error(__FILE__, __LINE__, "Character buffer overflow");
+	cbuffer[cbufidx++] = c;
+}
+
+void addwchar(short s)
+{
+	if(wbufidx >= sizeof(wbuffer))
+		internal_error(__FILE__, __LINE__, "Wide character buffer overflow");
+	wbuffer[wbufidx++] = (short)(s & 0xff);
+}
+
+string_t *get_buffered_cstring(void)
+{
+	string_t *str = new_string();
+	str->size = cbufidx;
+	str->type = str_char;
+	str->str.cstr = (char *)xmalloc(cbufidx+1);
+	memcpy(str->str.cstr, cbuffer, cbufidx);
+	str->str.cstr[cbufidx] = '\0';
+/*	printf("got cstring \"%s\"\n", str->str.cstr); */
+	return str;
+}
+
+string_t *get_buffered_wstring(void)
+{
+	string_t *str = new_string();
+	str->size = wbufidx;
+	str->type = str_unicode;
+	str->str.wstr = (short *)xmalloc(2*(wbufidx+1));
+	memcpy(str->str.wstr, wbuffer, wbufidx);
+	str->str.wstr[wbufidx] = 0;
+	return str;
+}
+
+string_t *make_string(char *s)
+{
+	string_t *str = new_string();
+	str->size = strlen(s);
+	str->type = str_char;
+	str->str.cstr = (char *)xmalloc(str->size+1);
+	memcpy(str->str.cstr, s, str->size+1);
+	return str;
+}
+
+/* Called from the parser to signal filename request */
+void set_yywf(void)
+{
+	push_to(yywf);
+}
+
+/* Called from the parser to signal preprocessor if case */
+void set_pp_ignore(int state)
+{
+	if(state)
+		push_to(pp_false);
+	else
+		pop_start();
+}
+
+/* Called from the parser to kill c-junk */
+void strip_til_semicolon(void)
+{
+	cjunk_tagline = line_number;
+	push_to(pp_strips);
+}
+
+void strip_til_parenthesis(void)
+{
+	cjunk_tagline = line_number;
+	stripplevel = 1;	/* One scanned already */
+	push_to(pp_stripp);
+}
+
+
diff --git a/tools/wrc/parser.y b/tools/wrc/parser.y
new file mode 100644
index 0000000..6186da9
--- /dev/null
+++ b/tools/wrc/parser.y
@@ -0,0 +1,2264 @@
+%{
+/*
+ * Copyright  Martin von Loewis, 1994
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ * 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.
+ *
+ * 16-Apr-1998 BS	- Raw data elements are now *optionally* seperated
+ *			  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
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include <config.h>
+#include "wrc.h"
+#include "utils.h"
+#include "newstruc.h"
+#include "dumpres.h"
+#include "preproc.h"
+#include "parser.h"
+
+#ifdef __BORLANDC__
+#pragma warn -sig
+#endif
+
+DWORD andmask;		/* Used to parse 'NOT NUMBER' expressions */
+int indialog = 0;	/* Signal flex that we're parsing a dialog */
+int want_rscname = 0;	/* Set when a resource's name is required */
+stringtable_t *tagstt;	/* Stringtable tag.
+			 * 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.
+			 */
+stringtable_t *sttres;	/* Stringtable resources. This holds the list of
+			 * stringtables with different lanuages
+			 */
+/* Set to the current options of the currently scanning stringtable */
+static int *tagstt_memopt;
+static characts_t *tagstt_characts;
+static version_t *tagstt_version;
+
+/* Prototypes of here defined functions */
+void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur);
+void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico);
+int alloc_cursor_id(void);
+int alloc_icon_id(void);
+void ins_stt_entry(stt_entry_t *ste);
+int check_stt_entry(stringtable_t *tabs, stt_entry_t *ste);
+event_t *get_event_head(event_t *p);
+control_t *get_control_head(control_t *p);
+ver_value_t *get_ver_value_head(ver_value_t *p);
+ver_block_t *get_ver_block_head(ver_block_t *p);
+resource_t *get_resource_head(resource_t *p);
+menuex_item_t *get_itemex_head(menuex_item_t *p);
+menu_item_t *get_item_head(menu_item_t *p);
+raw_data_t *merge_raw_data_str(raw_data_t *r1, string_t *str);
+raw_data_t *merge_raw_data_int(raw_data_t *r1, int i);
+raw_data_t *merge_raw_data(raw_data_t *r1, raw_data_t *r2);
+raw_data_t *str2raw_data(string_t *str);
+raw_data_t *int2raw_data(int i);
+raw_data_t *load_file(string_t *name);
+itemex_opt_t *new_itemex_opt(int id, int type, int state, int helpid);
+event_t *add_string_event(string_t *key, int id, int flags, event_t *prev);
+event_t *add_event(int key, int id, int flags, event_t *prev);
+dialogex_t *dialogex_version(version_t *v, dialogex_t *dlg);
+dialogex_t *dialogex_characteristics(characts_t *c, dialogex_t *dlg);
+dialogex_t *dialogex_language(language_t *l, dialogex_t *dlg);
+dialogex_t *dialogex_menu(name_id_t *m, dialogex_t *dlg);
+dialogex_t *dialogex_class(name_id_t *n, dialogex_t *dlg);
+dialogex_t *dialogex_font(font_id_t *f, dialogex_t *dlg);
+dialogex_t *dialogex_caption(string_t *s, dialogex_t *dlg);
+dialogex_t *dialogex_exstyle(int st, dialogex_t *dlg);
+dialogex_t *dialogex_style(int st, dialogex_t *dlg);
+name_id_t *convert_ctlclass(name_id_t *cls);
+control_t *ins_ctrl(int type, int style, control_t *ctrl, control_t *prev);
+dialog_t *dialog_version(version_t *v, dialog_t *dlg);
+dialog_t *dialog_characteristics(characts_t *c, dialog_t *dlg);
+dialog_t *dialog_language(language_t *l, dialog_t *dlg);
+dialog_t *dialog_menu(name_id_t *m, dialog_t *dlg);
+dialog_t *dialog_class(name_id_t *n, dialog_t *dlg);
+dialog_t *dialog_font(font_id_t *f, dialog_t *dlg);
+dialog_t *dialog_caption(string_t *s, dialog_t *dlg);
+dialog_t *dialog_exstyle(int st, dialog_t *dlg);
+dialog_t *dialog_style(int st, dialog_t *dlg);
+resource_t *build_stt_resources(stringtable_t *stthead);
+stringtable_t *find_stringtable(lvc_t *lvc);
+
+%}
+%union{
+	string_t	*str;
+	int		num;
+	int		*iptr;
+	resource_t	*res;
+	accelerator_t	*acc;
+	bitmap_t	*bmp;
+	cursor_t	*cur;
+	cursor_group_t	*curg;
+	dialog_t	*dlg;
+	dialogex_t	*dlgex;
+	font_t		*fnt;
+	icon_t		*ico;
+	icon_group_t	*icog;
+	menu_t		*men;
+	menuex_t	*menex;
+	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;
+	menuex_item_t	*menexitm;
+	itemex_opt_t	*exopt;
+	raw_data_t	*raw;
+	lvc_t		*lvc;
+	ver_value_t	*val;
+	ver_block_t	*blk;
+	ver_words_t	*verw;
+}
+
+%token tIF tIFDEF tIFNDEF tELSE tELIF tENDIF tDEFINED tNL
+%token tTYPEDEF tEXTERN
+%token <num> NUMBER
+%token <str> tSTRING IDENT FILENAME
+%token <raw> RAWDATA
+%token ACCELERATORS tBITMAP CURSOR DIALOG DIALOGEX MENU MENUEX MESSAGETABLE
+%token RCDATA VERSIONINFO STRINGTABLE FONT ICON
+%token AUTO3STATE AUTOCHECKBOX AUTORADIOBUTTON CHECKBOX DEFPUSHBUTTON
+%token PUSHBUTTON RADIOBUTTON STATE3 /* PUSHBOX */
+%token GROUPBOX COMBOBOX LISTBOX SCROLLBAR
+%token CONTROL EDITTEXT
+%token RTEXT CTEXT LTEXT
+%token BLOCK VALUE
+%token SHIFT ALT ASCII VIRTKEY GRAYED CHECKED INACTIVE NOINVERT
+%token tPURE IMPURE DISCARDABLE LOADONCALL PRELOAD tFIXED MOVEABLE
+%token CLASS CAPTION CHARACTERISTICS EXSTYLE STYLE VERSION LANGUAGE
+%token FILEVERSION PRODUCTVERSION FILEFLAGSMASK FILEOS FILETYPE FILEFLAGS FILESUBTYPE
+%token MENUBARBREAK MENUBREAK MENUITEM POPUP SEPARATOR
+%token HELP
+%token tSTRING IDENT RAWDATA
+%token tBEGIN tEND
+%left LOGOR
+%left LOGAND
+%left '|'
+%left '^'
+%left '&'
+%left EQ NE
+%left '<' LTE '>' GTE
+%left '+' '-'
+%left '*' '/'
+%right '~' '!' NOT
+
+%type <res> 	resource_file resource resources resource_definition
+%type <stt>	stringtable strings
+%type <fnt>	font
+%type <icog>	icon
+%type <acc> 	accelerators
+%type <event> 	events
+%type <bmp> 	bitmap
+%type <curg> 	cursor
+%type <dlg> 	dialog dlg_attributes
+%type <ctl> 	ctrls gen_ctrl lab_ctrl ctrl_desc iconinfo
+%type <iptr>	optional_style helpid
+%type <dlgex> 	dialogex dlgex_attribs
+%type <ctl>	exctrls gen_exctrl lab_exctrl exctrl_desc
+%type <rdt> 	rcdata
+%type <raw>	raw_data raw_elements opt_data
+%type <veri> 	versioninfo fix_version
+%type <verw>	ver_words
+%type <blk>	ver_blocks ver_block
+%type <val>	ver_values ver_value
+%type <men> 	menu
+%type <menitm>	item_definitions menu_body
+%type <menex>	menuex
+%type <menexitm> itemex_definitions menuex_body
+%type <exopt>	itemex_p_options itemex_options
+%type <msg> 	messagetable
+%type <usr> 	userres
+%type <num> 	item_options
+%type <nid> 	nameid ctlclass usertype
+%type <num> 	acc_opt
+%type <iptr>	loadmemopts lamo lama
+%type <fntid>	opt_font opt_exfont
+%type <lvc>	opt_lvc
+%type <lan>	opt_language
+%type <chars>	opt_characts
+%type <ver>	opt_version
+%type <num>	expr xpr dummy
+%type <iptr>	e_expr
+%type <iptr>	pp_expr pp_constant
+
+%%
+
+resource_file
+	: resources {
+		resource_t *rsc;
+		/* 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;
+		}
+		else
+			$1 = rsc;
+		/* Final statement before were done */
+		resource_top = get_resource_head($1);
+		}
+	;
+
+/* Resources are put into a linked list */
+resources
+	: /* Empty */		{ $$ = NULL; want_rscname = 1; }
+	| 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;
+		}
+		else if($1)
+		{
+			resource_t *tail = $1;
+			while(tail->next)
+				tail = tail->next;
+			$$ = tail;
+		}
+		else
+			$$ = NULL;
+		want_rscname = 1;
+		}
+	| resources preprocessor		{ $$ = $1; want_rscname = 1; }
+	| resources cjunk			{ $$ = $1; want_rscname = 1; }
+	;
+
+/* The buildin preprocessor */
+preprocessor
+	: tIF pp_expr tNL	{ pop_start(); push_if($2 ? *($2) : 0, 0, 0); if($2) free($2);}
+	| tIFDEF IDENT tNL	{ pop_start(); push_if(pp_lookup($2->str.cstr) != NULL, 0, 0); }
+	| tIFNDEF IDENT tNL	{ pop_start(); push_if(pp_lookup($2->str.cstr) == NULL, 0, 0); }
+	| tELIF pp_expr tNL	{ pop_start(); push_if($2 ? *($2) : 0, pop_if(), 0); if($2) free($2); }
+	| tELSE tNL		{ pop_start(); push_if(1, pop_if(), 0); }
+	| tENDIF tNL		{ pop_if(); }
+	;
+
+pp_expr	: pp_constant			{ $$ = $1; }
+	| pp_expr LOGOR pp_expr		{ $$ = new_int($1 && $3 ? (*$1 || *$3) : 0); if($1) free($1); if($3) free($3); }
+	| pp_expr LOGAND pp_expr	{ $$ = new_int($1 && $3 ? (*$1 && *$3) : 0); if($1) free($1); if($3) free($3); }
+	| pp_expr '+' pp_expr		{ $$ = new_int($1 && $3 ? (*$1  + *$3) : 0); if($1) free($1); if($3) free($3); }
+	| pp_expr '-' pp_expr		{ $$ = new_int($1 && $3 ? (*$1  - *$3) : 0); if($1) free($1); if($3) free($3); }
+	| pp_expr '^' pp_expr		{ $$ = new_int($1 && $3 ? (*$1  ^ *$3) : 0); if($1) free($1); if($3) free($3); }
+	| pp_expr EQ pp_expr		{ $$ = new_int($1 && $3 ? (*$1 == *$3) : 0); if($1) free($1); if($3) free($3); }
+	| pp_expr NE pp_expr		{ $$ = new_int($1 && $3 ? (*$1 != *$3) : 0); if($1) free($1); if($3) free($3); }
+	| pp_expr '<' pp_expr		{ $$ = new_int($1 && $3 ? (*$1  < *$3) : 0); if($1) free($1); if($3) free($3); }
+	| pp_expr '>' pp_expr		{ $$ = new_int($1 && $3 ? (*$1  > *$3) : 0); if($1) free($1); if($3) free($3); }
+	| pp_expr LTE pp_expr		{ $$ = new_int($1 && $3 ? (*$1 <= *$3) : 0); if($1) free($1); if($3) free($3); }
+	| pp_expr GTE pp_expr		{ $$ = new_int($1 && $3 ? (*$1 >= *$3) : 0); if($1) free($1); if($3) free($3); }
+	| '~' pp_expr			{ $$ = $2; if($2) *$2 = ~(*$2); }
+	| '+' pp_expr			{ $$ = $2; }
+	| '-' pp_expr			{ $$ = $2; if($2) *$2 = -(*$2); }
+	| '!' pp_expr			{ $$ = $2; if($2) *$2 = !(*$2); }
+	| '(' pp_expr ')'		{ $$ = $2; }
+	;
+
+pp_constant
+	: NUMBER			{ $$ = new_int($1); }
+	| IDENT				{ $$ = NULL; }
+	| tDEFINED IDENT		{ $$ = new_int(pp_lookup($2->str.cstr) != NULL); }
+	| tDEFINED '(' IDENT ')'	{ $$ = new_int(pp_lookup($3->str.cstr) != NULL); }
+	;
+
+/* C ignore stuff */
+cjunk	: tTYPEDEF			{ strip_til_semicolon(); }
+	| tEXTERN			{ strip_til_semicolon(); }
+	| IDENT IDENT			{ strip_til_semicolon(); }
+	| IDENT '('			{ strip_til_parenthesis(); }
+	| IDENT '*'			{ strip_til_semicolon(); }
+	;
+
+/* Parse top level resource definitions etc. */
+resource
+	: nameid resource_definition {
+		$$ = $2;
+		if($$)
+		{
+			$$->name = $1;
+			if($1->type == name_ord)
+			{
+				chat("Got %s (%d)",get_typename($2),$1->name.i_name);
+			}
+			else if($1->type == name_str)
+			{
+				chat("Got %s (%s)",get_typename($2),$1->name.s_name->str.cstr);
+			}
+		}
+		}
+	| 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;
+		chat("Got STRINGTABLE");
+		}
+	| opt_language {
+		if(!win32)
+			yywarning("LANGUAGE not supported in 16-bit mode");
+		if(currentlanguage)
+			free(currentlanguage);
+		currentlanguage = $1;
+		$$ = NULL;
+		}
+	;
+
+/* FIXME:
+ * The problem here is that MENU MENU {...} is a valid (!) resource.
+ * The name-identifier is "MENU". We cannot parse this without generating
+ * an error. It would mean that a list of keywords must be added here
+ * and converted into a valid name_id_t structure.
+ */
+nameid	: expr	{
+		$$ = new_name_id();
+		$$->type = name_ord;
+		$$->name.i_name = $1;
+		want_rscname = 0;
+		}
+	| IDENT	{
+		$$ = new_name_id();
+		$$->type = name_str;
+		$$->name.s_name = $1;
+		want_rscname = 0;
+		}
+	;
+
+/* get the value for a single resource*/
+resource_definition
+	: accelerators	{ $$ = new_resource(res_acc, $1, $1->memopt, $1->lvc.language); }
+	| bitmap	{ $$ = new_resource(res_bmp, $1, $1->memopt, currentlanguage); }
+	| cursor {
+		resource_t *rsc;
+		cursor_t *cur;
+		$$ = rsc = new_resource(res_curg, $1, $1->memopt, currentlanguage);
+		for(cur = $1->cursorlist; cur; cur = cur->next)
+		{
+			rsc->prev = new_resource(res_cur, cur, $1->memopt, currentlanguage);
+			rsc->prev->next = rsc;
+			rsc = rsc->prev;
+			rsc->name = new_name_id();
+			rsc->name->type = name_ord;
+			rsc->name->name.i_name = cur->id;
+		}
+		}
+	| dialog	{ $$ = new_resource(res_dlg, $1, $1->memopt, $1->lvc.language); }
+	| dialogex {
+		if(win32)
+			$$ = new_resource(res_dlgex, $1, $1->memopt, $1->lvc.language);
+		else
+			$$ = NULL;
+		}
+	| font		{ $$=new_resource(res_fnt, $1, $1->memopt, currentlanguage); }
+	| icon {
+		resource_t *rsc;
+		icon_t *ico;
+		$$ = rsc = new_resource(res_icog, $1, $1->memopt, currentlanguage);
+		for(ico = $1->iconlist; ico; ico = ico->next)
+		{
+			rsc->prev = new_resource(res_ico, ico, $1->memopt, currentlanguage);
+			rsc->prev->next = rsc;
+			rsc = rsc->prev;
+			rsc->name = new_name_id();
+			rsc->name->type = name_ord;
+			rsc->name->name.i_name = ico->id;
+		}
+		}
+	| menu		{ $$ = new_resource(res_men, $1, $1->memopt, $1->lvc.language); }
+	| menuex {
+		if(win32)
+			$$ = new_resource(res_menex, $1, $1->memopt, $1->lvc.language);
+		else
+			$$ = NULL;
+		}
+	| messagetable	{ $$ = new_resource(res_msg, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, currentlanguage); }
+	| rcdata	{ $$ = new_resource(res_rdt, $1, $1->memopt, $1->lvc.language); }
+	| userres	{ $$ = new_resource(res_usr, $1, $1->memopt, currentlanguage); }
+	| versioninfo	{ $$ = new_resource(res_ver, $1, WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE, currentlanguage); }
+	;
+
+/* ------------------------------ Bitmap ------------------------------ */
+bitmap	: tBITMAP loadmemopts FILENAME	{ $$ = new_bitmap(load_file($3), $2); }
+	| tBITMAP loadmemopts raw_data	{ $$ = new_bitmap($3, $2); }
+	;
+
+/* ------------------------------ Cursor ------------------------------ */
+cursor	: CURSOR loadmemopts FILENAME	{ $$ = new_cursor_group(load_file($3), $2); }
+	| CURSOR loadmemopts raw_data	{ $$ = new_cursor_group($3, $2); }
+	;
+
+/* ------------------------------ Font ------------------------------ */
+/* FIXME: Should we allow raw_data here? */
+font	: FONT loadmemopts FILENAME	{ $$ = new_font(load_file($3), $2); }
+	;
+
+/* ------------------------------ Icon ------------------------------ */
+icon	: ICON loadmemopts FILENAME	{ $$ = new_icon_group(load_file($3), $2); }
+	| ICON loadmemopts raw_data	{ $$ = new_icon_group($3, $2); }
+	;
+
+/* ------------------------------ 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
+	: MESSAGETABLE FILENAME	{
+		if(!win32)
+			yywarning("MESSAGETABLE not supported in 16-bit mode");
+		$$ = new_messagetable(load_file($2));
+		}
+	;
+
+/* ------------------------------ RCData ------------------------------ */
+rcdata	: RCDATA loadmemopts opt_lvc raw_data {
+		$$ = new_rcdata($4, $2);
+		if($3)
+		{
+			$$->lvc = *($3);
+			free($3);
+		}
+		if(!$$->lvc.language)
+			$$->lvc.language = dup_language(currentlanguage);
+		}
+	;
+
+/* ------------------------------ UserType ------------------------------ */
+userres	: usertype loadmemopts FILENAME	{ $$ = new_user($1, load_file($3), $2); }
+	| usertype loadmemopts raw_data	{ $$ = new_user($1, $3, $2); }
+	;
+
+/* NOTE: This here is an exception where I do not allow an expression.
+ * Reason for this is that it is not possible to set the 'yywf' condition
+ * for flex if loadmemopts is empty. Reading an expression requires a
+ * lookahead to determine its end. In this case here, that would mean that
+ * the filename has been read as IDENT or tSTRING, which is incorrect.
+ * Note also that IDENT cannot be used as a file-name because it is lacking
+ * the '.'.
+ */
+
+/* I also allow string identifiers as classtypes. Not MS implemented, but
+ * seems to be reasonable to implement.
+ */
+/* Allowing anything else than NUMBER makes it very hard to get rid of
+ * prototypes. So, I remove IDENT to be able to get prototypes out of the
+ * world.
+ */
+usertype: NUMBER {
+		$$ = new_name_id();
+		$$->type = name_ord;
+		$$->name.i_name = $1;
+		set_yywf();
+		}
+/*	| IDENT {
+		$$ = new_name_id();
+		$$->type = name_str;
+		$$->name.s_name = $1;
+		set_yywf();
+		}
+*/	| tSTRING {
+		$$ = new_name_id();
+		$$->type = name_str;
+		$$->name.s_name = $1;
+		set_yywf();
+		}
+	;
+
+/* ------------------------------ Accelerator ------------------------------ */
+accelerators
+	: ACCELERATORS loadmemopts opt_lvc tBEGIN events tEND {
+		$$ = new_accelerator();
+		if($2)
+		{
+			$$->memopt = *($2);
+			free($2);
+		}
+		else
+		{
+			$$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
+		}
+		if(!$5)
+			yyerror("Accelerator table must have at least one entry");
+		$$->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); }
+	;
+
+acc_opt	: /* Empty */		{ $$=0; }
+	| acc_opt ',' NOINVERT 	{ $$=$1 | WRC_AF_NOINVERT; }
+	| acc_opt ',' SHIFT	{ $$=$1 | WRC_AF_SHIFT; }
+	| acc_opt ',' CONTROL	{ $$=$1 | WRC_AF_CONTROL; }
+	| acc_opt ',' ALT	{ $$=$1 | WRC_AF_ALT; }
+	| acc_opt ',' ASCII	{ $$=$1 | WRC_AF_ASCII; }
+	| acc_opt ',' VIRTKEY	{ $$=$1 | WRC_AF_VIRTKEY; }
+	;
+
+/* ------------------------------ Dialog ------------------------------ */
+/* FIXME: Support EXSTYLE in the dialog line itself */
+dialog	: DIALOG loadmemopts expr ',' expr ',' expr ',' expr dlg_attributes
+	  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)
+		{
+			$$->style = WS_POPUP;
+			$$->gotstyle = TRUE;
+		}
+		if($$->title)
+			$$->style |= WS_CAPTION;
+		if($$->font)
+			$$->style |= DS_SETFONT;
+		indialog = FALSE;
+		if(!$$->lvc.language)
+			$$->lvc.language = dup_language(currentlanguage);
+		}
+	;
+
+dlg_attributes
+	: /* Empty */			{ $$=new_dialog(); }
+	| dlg_attributes STYLE expr	{ $$=dialog_style($3,$1); }
+	| dlg_attributes EXSTYLE expr	{ $$=dialog_exstyle($3,$1); }
+	| dlg_attributes CAPTION tSTRING { $$=dialog_caption($3,$1); }
+	| dlg_attributes opt_font	{ $$=dialog_font($2,$1); }
+	| dlg_attributes CLASS nameid	{ $$=dialog_class($3,$1); }
+	| dlg_attributes MENU 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); }
+	;
+
+ctrls	: /* Empty */				{ $$ = NULL; }
+	| ctrls CONTROL		gen_ctrl	{ $$=ins_ctrl(-1, 0, $3, $1); }
+	| ctrls EDITTEXT	ctrl_desc	{ $$=ins_ctrl(CT_EDIT, 0, $3, $1); }
+	| ctrls LISTBOX		ctrl_desc	{ $$=ins_ctrl(CT_LISTBOX, 0, $3, $1); }
+	| ctrls COMBOBOX	ctrl_desc	{ $$=ins_ctrl(CT_COMBOBOX, 0, $3, $1); }
+	| ctrls SCROLLBAR	ctrl_desc	{ $$=ins_ctrl(CT_SCROLLBAR, 0, $3, $1); }
+	| ctrls CHECKBOX	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_CHECKBOX, $3, $1); }
+	| ctrls DEFPUSHBUTTON	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_DEFPUSHBUTTON, $3, $1); }
+	| ctrls GROUPBOX	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_GROUPBOX, $3, $1);}
+	| ctrls PUSHBUTTON	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_PUSHBUTTON, $3, $1); }
+/*	| ctrls PUSHBOX		lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
+	| ctrls RADIOBUTTON	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_RADIOBUTTON, $3, $1); }
+	| ctrls AUTO3STATE	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTO3STATE, $3, $1); }
+	| ctrls STATE3		lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_3STATE, $3, $1); }
+	| ctrls AUTOCHECKBOX	lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTOCHECKBOX, $3, $1); }
+	| ctrls AUTORADIOBUTTON lab_ctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTORADIOBUTTON, $3, $1); }
+	| ctrls LTEXT		lab_ctrl	{ $$=ins_ctrl(CT_STATIC, SS_LEFT, $3, $1); }
+	| ctrls CTEXT		lab_ctrl	{ $$=ins_ctrl(CT_STATIC, SS_CENTER, $3, $1); }
+	| ctrls RTEXT		lab_ctrl	{ $$=ins_ctrl(CT_STATIC, SS_RIGHT, $3, $1); }
+	/* special treatment for icons, as the extent is optional */
+	| ctrls ICON tSTRING ',' expr ',' expr ',' expr iconinfo {
+		$10->title = $3;
+		$10->id = $5;
+		$10->x = $7;
+		$10->y = $9;
+		$$ = ins_ctrl(CT_STATIC, SS_ICON, $10, $1);
+		}
+	;
+
+lab_ctrl
+	: tSTRING ',' expr ',' expr ',' expr ',' expr ',' expr optional_style {
+		$$=new_control();
+		$$->title = $1;
+		$$->id = $3;
+		$$->x = $5;
+		$$->y = $7;
+		$$->width = $9;
+		$$->height = $11;
+		if($12)
+		{
+			$$->style = *($12);
+			$$->gotstyle = TRUE;
+			free($12);
+		}
+		}
+	;
+
+ctrl_desc
+	: expr ',' expr ',' expr ',' expr ',' expr optional_style {
+		$$ = new_control();
+		$$->id = $1;
+		$$->x = $3;
+		$$->y = $5;
+		$$->width = $7;
+		$$->height = $9;
+		if($10)
+		{
+			$$->style = *($10);
+			$$->gotstyle = TRUE;
+			free($10);
+		}
+		}
+	;
+
+iconinfo: /* Empty */
+		{ $$ = new_control(); }
+
+	| ',' expr ',' expr {
+		$$ = new_control();
+		$$->width = $2;
+		$$->height = $4;
+		}
+	| ',' expr ',' expr ',' expr {
+		$$ = new_control();
+		$$->width = $2;
+		$$->height = $4;
+		$$->style = $6;
+		$$->gotstyle = TRUE;
+		}
+	| ',' expr ',' expr ',' expr ',' expr {
+		$$ = new_control();
+		$$->width = $2;
+		$$->height = $4;
+		$$->style = $6;
+		$$->gotstyle = TRUE;
+		$$->exstyle = $8;
+		$$->gotexstyle = TRUE;
+		}
+	;
+
+gen_ctrl: tSTRING ',' expr ',' ctlclass ',' expr ',' expr ',' expr ',' expr ',' expr ',' expr {
+		$$=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;
+		}
+	| tSTRING ',' expr ',' ctlclass ',' expr ',' expr ',' expr ',' expr ',' expr {
+		$$=new_control();
+		$$->title = $1;
+		$$->id = $3;
+		$$->ctlclass = convert_ctlclass($5);
+		$$->style = $7;
+		$$->gotstyle = TRUE;
+		$$->x = $9;
+		$$->y = $11;
+		$$->width = $13;
+		$$->height = $15;
+		}
+	;
+
+opt_font
+	: FONT expr ',' tSTRING	{ $$ = new_font_id($2, $4, 0, 0); }
+	;
+
+optional_style		/* Abbused once to get optional ExStyle */
+	: /* Empty */	{ $$ = NULL; }
+	| ',' expr	{ $$ = new_int($2); }
+	;
+
+ctlclass
+	: expr	{
+		$$ = new_name_id();
+		$$->type = name_ord;
+		$$->name.i_name = $1;
+		}
+	| tSTRING {
+		$$ = new_name_id();
+		$$->type = name_str;
+		$$->name.s_name = $1;
+		}
+	;
+
+/* ------------------------------ DialogEx ------------------------------ */
+dialogex: DIALOGEX loadmemopts expr ',' expr ',' expr ',' expr helpid dlgex_attribs
+	  tBEGIN  exctrls tEND {
+		if(!win32)
+			yywarning("DIALOGEX not supported in 16-bit mode");
+		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;
+		if(!$$->gotstyle)
+		{
+			$$->style = WS_POPUP;
+			$$->gotstyle = TRUE;
+		}
+		if($$->title)
+			$$->style |= WS_CAPTION;
+		if($$->font)
+			$$->style |= DS_SETFONT;
+		indialog = FALSE;
+		if(!$$->lvc.language)
+			$$->lvc.language = dup_language(currentlanguage);
+		}
+	;
+
+dlgex_attribs
+	: /* Empty */			{ $$=new_dialogex(); }
+	| dlgex_attribs STYLE expr	{ $$=dialogex_style($3,$1); }
+	| dlgex_attribs EXSTYLE expr	{ $$=dialogex_exstyle($3,$1); }
+	| dlgex_attribs CAPTION tSTRING { $$=dialogex_caption($3,$1); }
+	| dlgex_attribs opt_exfont	{ $$=dialogex_font($2,$1); }
+	| dlgex_attribs CLASS nameid	{ $$=dialogex_class($3,$1); }
+	| dlgex_attribs MENU nameid	{ $$=dialogex_menu($3,$1); }
+	| dlgex_attribs opt_language	{ $$=dialogex_language($2,$1); }
+	| dlgex_attribs opt_characts	{ $$=dialogex_characteristics($2,$1); }
+	| dlgex_attribs opt_version	{ $$=dialogex_version($2,$1); }
+	;
+
+exctrls	: /* Empty */				{ $$ = NULL; }
+	| exctrls CONTROL	gen_exctrl	{ $$=ins_ctrl(-1, 0, $3, $1); }
+	| exctrls EDITTEXT	exctrl_desc	{ $$=ins_ctrl(CT_EDIT, 0, $3, $1); }
+	| exctrls LISTBOX	exctrl_desc	{ $$=ins_ctrl(CT_LISTBOX, 0, $3, $1); }
+	| exctrls COMBOBOX	exctrl_desc	{ $$=ins_ctrl(CT_COMBOBOX, 0, $3, $1); }
+	| exctrls SCROLLBAR	exctrl_desc	{ $$=ins_ctrl(CT_SCROLLBAR, 0, $3, $1); }
+	| exctrls CHECKBOX	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_CHECKBOX, $3, $1); }
+	| exctrls DEFPUSHBUTTON	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_DEFPUSHBUTTON, $3, $1); }
+	| exctrls GROUPBOX	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_GROUPBOX, $3, $1);}
+	| exctrls PUSHBUTTON	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_PUSHBUTTON, $3, $1); }
+/*	| exctrls PUSHBOX	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_PUSHBOX, $3, $1); } */
+	| exctrls RADIOBUTTON	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_RADIOBUTTON, $3, $1); }
+	| exctrls AUTO3STATE	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTO3STATE, $3, $1); }
+	| exctrls STATE3	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_3STATE, $3, $1); }
+	| exctrls AUTOCHECKBOX	lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTOCHECKBOX, $3, $1); }
+	| exctrls AUTORADIOBUTTON lab_exctrl	{ $$=ins_ctrl(CT_BUTTON, BS_AUTORADIOBUTTON, $3, $1); }
+	| exctrls LTEXT		lab_exctrl	{ $$=ins_ctrl(CT_STATIC, SS_LEFT, $3, $1); }
+	| exctrls CTEXT		lab_exctrl	{ $$=ins_ctrl(CT_STATIC, SS_CENTER, $3, $1); }
+	| exctrls RTEXT		lab_exctrl	{ $$=ins_ctrl(CT_STATIC, SS_RIGHT, $3, $1); }
+	/* special treatment for icons, as the extent is optional */
+	| exctrls ICON tSTRING ',' expr ',' expr ',' expr iconinfo {
+		$10->title = $3;
+		$10->id = $5;
+		$10->x = $7;
+		$10->y = $9;
+		$$ = ins_ctrl(CT_STATIC, SS_ICON, $10, $1);
+		}
+	;
+
+gen_exctrl
+	: tSTRING ',' expr ',' ctlclass ',' expr ',' expr ',' expr ',' expr ','
+	  expr ',' e_expr helpid opt_data {
+		$$=new_control();
+		$$->title = $1;
+		$$->id = $3;
+		$$->ctlclass = convert_ctlclass($5);
+		$$->style = $7;
+		$$->gotstyle = TRUE;
+		$$->x = $9;
+		$$->y = $11;
+		$$->width = $13;
+		$$->height = $15;
+		if($17)
+		{
+			$$->exstyle = *($17);
+			$$->gotexstyle = TRUE;
+			free($17);
+		}
+		if($18)
+		{
+			$$->helpid = *($18);
+			$$->gothelpid = TRUE;
+			free($18);
+		}
+		$$->extra = $19;
+		}
+	| tSTRING ',' expr ',' ctlclass ',' expr ',' expr ',' expr ',' expr ',' expr opt_data {
+		$$=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
+	: tSTRING ',' expr ',' expr ',' expr ',' expr ',' expr optional_style opt_data {
+		$$=new_control();
+		$$->title = $1;
+		$$->id = $3;
+		$$->x = $5;
+		$$->y = $7;
+		$$->width = $9;
+		$$->height = $11;
+		if($12)
+		{
+			$$->style = *($12);
+			$$->gotstyle = TRUE;
+			free($12);
+		}
+		$$->extra = $13;
+		}
+	;
+
+exctrl_desc
+	: expr ',' expr ',' expr ',' expr ',' expr optional_style opt_data {
+		$$ = new_control();
+		$$->id = $1;
+		$$->x = $3;
+		$$->y = $5;
+		$$->width = $7;
+		$$->height = $9;
+		if($10)
+		{
+			$$->style = *($10);
+			$$->gotstyle = TRUE;
+			free($10);
+		}
+		$$->extra = $11;
+		}
+	;
+
+opt_data: /* Empty */	{ $$ = NULL; }
+	| raw_data	{ $$ = $1; }
+	;
+
+helpid	: /* Empty */	{ $$ = NULL; }
+	| ',' expr	{ $$ = new_int($2); }
+	;
+
+opt_exfont
+	: FONT expr ',' tSTRING ',' expr ',' expr	{ $$ = new_font_id($2, $4, $6, $8); }
+	;
+
+/* ------------------------------ Menu ------------------------------ */
+menu	: MENU loadmemopts opt_lvc menu_body {
+		if(!$4)
+			yyerror("Menu must contain items");
+		$$ = 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;}
+	| item_definitions MENUITEM tSTRING ',' expr item_options {
+		$$=new_menu_item();
+		$$->prev = $1;
+		if($1)
+			$1->next = $$;
+		$$->id =  $5;
+		$$->state = $6;
+		$$->name = $3;
+		}
+	| item_definitions MENUITEM SEPARATOR {
+		$$=new_menu_item();
+		$$->prev = $1;
+		if($1)
+			$1->next = $$;
+		}
+	| item_definitions POPUP tSTRING item_options menu_body {
+		$$ = 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
+	: /* Empty */			{ $$ = 0; }
+	| ',' CHECKED	item_options	{ $$ = $3 | MF_CHECKED; }
+	| ',' GRAYED	item_options	{ $$ = $3 | MF_GRAYED; }
+	| ',' HELP	item_options	{ $$ = $3 | MF_HELP; }
+	| ',' INACTIVE	item_options	{ $$ = $3 | MF_DISABLED; }
+	| ',' MENUBARBREAK item_options	{ $$ = $3 | MF_MENUBARBREAK; }
+	| ',' MENUBREAK	item_options	{ $$ = $3 | MF_MENUBREAK; }
+	;
+
+/* ------------------------------ MenuEx ------------------------------ */
+menuex	: MENUEX loadmemopts opt_lvc menuex_body	{
+		if(!win32)
+			yywarning("MENUEX not supported in 16-bit mode");
+		if(!$4)
+			yyerror("MenuEx must contain items");
+		$$ = new_menuex();
+		if($2)
+		{
+			$$->memopt = *($2);
+			free($2);
+		}
+		else
+			$$->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
+		$$->items = get_itemex_head($4);
+		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; }
+	| itemex_definitions MENUITEM tSTRING itemex_options {
+		$$ = new_menuex_item();
+		$$->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);
+		}
+	| itemex_definitions MENUITEM SEPARATOR {
+		$$ = new_menuex_item();
+		$$->prev = $1;
+		if($1)
+			$1->next = $$;
+		}
+	| itemex_definitions POPUP tSTRING itemex_p_options menuex_body {
+		$$ = new_menuex_item();
+		$$->prev = $1;
+		if($1)
+			$1->next = $$;
+		$$->popup = get_itemex_head($5);
+		$$->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;
+		if($2) free($2);
+		if($4) free($4);
+		}
+	| ',' e_expr ',' e_expr ',' expr {
+		$$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $6, 0);
+		$$->gotid = TRUE;
+		$$->gottype = TRUE;
+		$$->gotstate = TRUE;
+		if($2) free($2);
+		if($4) free($4);
+		}
+	;
+
+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);
+		if($2) free($2);
+		$$->gotid = TRUE;
+		$$->gottype = TRUE;
+		}
+	| ',' e_expr ',' e_expr ',' expr {
+		$$ = new_itemex_opt($2 ? *($2) : 0, $4 ? *($4) : 0, $6, 0);
+		if($2) free($2);
+		if($4) free($4);
+		$$->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);
+		if($2) free($2);
+		if($4) free($4);
+		if($6) free($6);
+		$$->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)
+		{
+			yyerror("Stringtable must have at least one entry");
+		}
+		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 */
+		}
+		if(tagstt_memopt)
+		{
+			free(tagstt_memopt);
+			tagstt_memopt = NULL;
+		}
+
+		$$ = tagstt;
+		}
+	;
+
+/* This is to get the language of the currently parsed stringtable */
+stt_head: STRINGTABLE loadmemopts opt_lvc {
+		if((tagstt = find_stringtable($3)) == NULL)
+			tagstt = new_stringtable($3);
+		tagstt_memopt = $2;
+		tagstt_version = $3->version;
+		tagstt_characts = $3->characts;
+		if($3)
+			free($3);
+		}
+	;
+
+strings	: /* Empty */	{ $$ = NULL; }
+	| strings expr opt_comma tSTRING {
+		int i;
+		assert(tagstt != NULL);
+		/* Search for the ID */
+		for(i = 0; i < tagstt->nentries; i++)
+		{
+			if(tagstt->entries[i].id == $2)
+				yyerror("Stringtable ID %d already in use", $2);
+		}
+		/* 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;
+
+		if(!win32 && $4->size > 254)
+			yyerror("Stringtable entry more than 254 characters");
+		if(win32 && $4->size > 65534) /* Hmm..., does this happen? */
+			yyerror("Stringtable entry more than 65534 characters (probably something else that went wrong)");
+		$$ = tagstt;
+		}
+	;
+
+opt_comma	/* There seem to be two ways to specify a stringtable... */
+	: /* Empty */
+	| ','
+	;
+
+/* ------------------------------ VersionInfo ------------------------------ */
+versioninfo
+	: VERSIONINFO fix_version tBEGIN ver_blocks tEND {
+		$$ = $2;
+		$2->blocks = get_ver_block_head($4);
+		}
+	;
+
+fix_version
+	: /* Empty */			{ $$ = new_versioninfo(); }
+	| fix_version FILEVERSION expr ',' expr ',' expr ',' expr {
+		if($1->gotit.fv)
+			yyerror("FILEVERSION already defined");
+		$$ = $1;
+		$$->filever_maj1 = $3;
+		$$->filever_maj2 = $5;
+		$$->filever_min1 = $7;
+		$$->filever_min2 = $9;
+		$$->gotit.fv = 1;
+		}
+	| fix_version PRODUCTVERSION expr ',' expr ',' expr ',' expr {
+		if($1->gotit.pv)
+			yyerror("PRODUCTVERSION already defined");
+		$$ = $1;
+		$$->prodver_maj1 = $3;
+		$$->prodver_maj2 = $5;
+		$$->prodver_min1 = $7;
+		$$->prodver_min2 = $9;
+		$$->gotit.pv = 1;
+		}
+	| fix_version FILEFLAGS expr {
+		if($1->gotit.ff)
+			yyerror("FILEFLAGS already defined");
+		$$ = $1;
+		$$->fileflags = $3;
+		$$->gotit.ff = 1;
+		}
+	| fix_version FILEFLAGSMASK expr {
+		if($1->gotit.ffm)
+			yyerror("FILEFLAGSMASK already defined");
+		$$ = $1;
+		$$->fileflagsmask = $3;
+		$$->gotit.ffm = 1;
+		}
+	| fix_version FILEOS expr {
+		if($1->gotit.fo)
+			yyerror("FILEOS already defined");
+		$$ = $1;
+		$$->fileos = $3;
+		$$->gotit.fo = 1;
+		}
+	| fix_version FILETYPE expr {
+		if($1->gotit.ft)
+			yyerror("FILETYPE already defined");
+		$$ = $1;
+		$$->filetype = $3;
+		$$->gotit.ft = 1;
+		}
+	| fix_version FILESUBTYPE expr {
+		if($1->gotit.fst)
+			yyerror("FILESUBTYPE already defined");
+		$$ = $1;
+		$$->filesubtype = $3;
+		$$->gotit.fst = 1;
+		}
+	;
+
+ver_blocks
+	: /* Empty */			{ $$ = NULL; }
+	| ver_blocks ver_block {
+		$$ = $2;
+		$$->prev = $1;
+		if($1)
+			$1->next = $$;
+		}
+	;
+
+ver_block
+	: BLOCK tSTRING tBEGIN ver_values tEND {
+		$$ = 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;
+		}
+	| VALUE tSTRING ',' tSTRING {
+		$$ = new_ver_value();
+		$$->type = val_str;
+		$$->key = $2;
+		$$->value.str = $4;
+		}
+	| VALUE tSTRING ',' ver_words {
+		$$ = 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); }
+	;
+
+/* ------------------------------ 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;
+		}
+		}
+	;
+
+lamo	: PRELOAD	{ $$ = new_int(WRC_MO_PRELOAD); }
+	| MOVEABLE	{ $$ = new_int(WRC_MO_MOVEABLE); }
+	| DISCARDABLE	{ $$ = new_int(WRC_MO_DISCARDABLE); }
+	| tPURE		{ $$ = new_int(WRC_MO_PURE); }
+	;
+
+lama	: LOADONCALL	{ $$ = new_int(~WRC_MO_PRELOAD); }
+	| tFIXED	{ $$ = new_int(~WRC_MO_MOVEABLE); }
+	| IMPURE	{ $$ = new_int(~WRC_MO_PURE); }
+	;
+
+/* ------------------------------ Win32 options ------------------------------ */
+opt_lvc	: /* Empty */		{ $$ = new_lvc(); }
+	| opt_lvc opt_language {
+		if(!win32)
+			yywarning("LANGUAGE not supported in 16-bit mode");
+		if($1->language)
+			yyerror("Language already defined");
+		$$ = $1;
+		$1->language = $2;
+		}
+	| opt_lvc opt_characts {
+		if(!win32)
+			yywarning("CHARACTERISTICS not supported in 16-bit mode");
+		if($1->characts)
+			yyerror("Characteristics already defined");
+		$$ = $1;
+		$1->characts = $2;
+		}
+	| opt_lvc opt_version {
+		if(!win32)
+			yywarning("VERSION not supported in 16-bit mode");
+		if($1->version)
+			yyerror("Version already defined");
+		$$ = $1;
+		$1->version = $2;
+		}
+	;
+
+opt_language
+	: LANGUAGE expr ',' expr	{ $$ = new_language($2, $4); }
+	;
+
+opt_characts
+	: CHARACTERISTICS expr		{ $$ = new_characts($2); }
+	;
+
+opt_version
+	: VERSION expr			{ $$ = new_version($2); }
+	;
+
+/* ------------------------------ Raw data handking ------------------------------ */
+raw_data: tBEGIN raw_elements tEND	{ $$ = $2; }
+	;
+
+raw_elements
+	: RAWDATA			{ $$ = $1; }
+	| NUMBER			{ $$ = int2raw_data($1); }
+	| tSTRING			{ $$ = str2raw_data($1); }
+	| raw_elements opt_comma RAWDATA   { $$ = merge_raw_data($1, $3); free($3->data); free($3); }
+	| raw_elements opt_comma NUMBER	   { $$ = merge_raw_data_int($1, $3); }
+	| raw_elements opt_comma tSTRING   { $$ = merge_raw_data_str($1, $3); }
+	;
+
+/* ------------------------------ Win32 expressions ------------------------------ */
+/* All win16 numbers are also handled here. This is inconsistent with MS'
+ * resource compiler, but what the heck, its just handy to have.
+ */
+e_expr	: /* Empty */	{ $$ = 0; }
+	| expr		{ $$ = new_int($1); }
+	;
+expr	: dummy xpr	{ $$ = ($2) & andmask; }
+	;
+
+dummy	: /* Empty */	{ $$ = 0; andmask = -1; }
+	;
+
+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); }
+	| '~' xpr	{ $$ = ~($2); }
+	| '-' xpr	{ $$ = -($2); }		/* FIXME: shift/reduce conflict */
+/*	| '+' xpr	{ $$ = $2; } */
+	| '(' xpr ')'	{ $$ = $2; }
+	| NUMBER	{ $$ = $1; want_rscname = 0; }
+	| NOT NUMBER	{ $$ = 0; andmask &= ~($2); }
+	;
+%%
+/* Dialog specific functions */
+dialog_t *dialog_style(int st, dialog_t *dlg)
+{
+	DWORD s = 0;
+	assert(dlg != NULL);
+	if(dlg->gotstyle)
+	{
+		yywarning("Style already defined, or-ing together");
+		s = dlg->style;
+	}
+	dlg->style = st | s;
+	dlg->gotstyle = TRUE;
+	return dlg;
+}
+
+dialog_t *dialog_exstyle(int st, dialog_t *dlg)
+{
+	DWORD s = 0;
+	assert(dlg != NULL);
+	if(dlg->gotexstyle)
+	{
+		yywarning("ExStyle already defined, or-ing together");
+		s = dlg->style;
+	}
+	dlg->exstyle = st | s;
+	dlg->gotexstyle = TRUE;
+	return dlg;
+}
+
+dialog_t *dialog_caption(string_t *s, dialog_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->title)
+		yyerror("Caption already defined");
+	dlg->title = s;
+	return dlg;
+}
+
+dialog_t *dialog_font(font_id_t *f, dialog_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->font)
+		yyerror("Font already defined");
+	dlg->font = f;
+	return dlg;
+}
+
+dialog_t *dialog_class(name_id_t *n, dialog_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->dlgclass)
+		yyerror("Class already defined");
+	dlg->dlgclass = n;
+	return dlg;
+}
+
+dialog_t *dialog_menu(name_id_t *m, dialog_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->menu)
+		yyerror("Menu already defined");
+	dlg->menu = m;
+	return dlg;
+}
+
+dialog_t *dialog_language(language_t *l, dialog_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->lvc.language)
+		yyerror("Language already defined");
+	dlg->lvc.language = l;
+	return dlg;
+}
+
+dialog_t *dialog_characteristics(characts_t *c, dialog_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->lvc.characts)
+		yyerror("Characteristics already defined");
+	dlg->lvc.characts = c;
+	return dlg;
+}
+
+dialog_t *dialog_version(version_t *v, dialog_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->lvc.version)
+		yyerror("Version already defined");
+	dlg->lvc.version = v;
+	return dlg;
+}
+
+/* Controls specific functions */
+control_t *ins_ctrl(int type, int style, control_t *ctrl, control_t *prev)
+{
+	assert(ctrl != NULL);
+	ctrl->prev = prev;
+	if(prev)
+		prev->next = ctrl;
+	if(type != -1)
+	{
+		ctrl->ctlclass = new_name_id();
+		ctrl->ctlclass->type = name_ord;
+		ctrl->ctlclass->name.i_name = type;
+	}
+
+	/* Hm... this seems to be jammed in at all time... */
+	ctrl->style |= WS_CHILD | WS_VISIBLE;
+	switch(type)
+	{
+	case CT_BUTTON:
+		ctrl->style |= style;
+		if(style != BS_GROUPBOX && style != BS_RADIOBUTTON)
+			ctrl->style |= WS_TABSTOP;
+		break;
+	case CT_EDIT:
+		ctrl->style |= WS_TABSTOP | WS_BORDER;
+		break;
+	case CT_LISTBOX:
+		ctrl->style |= LBS_NOTIFY | WS_BORDER;
+		break;
+	case CT_COMBOBOX:
+		ctrl->style |= CBS_SIMPLE;
+		break;
+	case CT_STATIC:
+		ctrl->style |= style;
+		if(style == SS_CENTER || style == SS_LEFT || style == SS_RIGHT)
+			ctrl->style |= WS_GROUP;
+		break;
+	}
+
+	if(!ctrl->gotstyle)	/* Handle default style setting */
+	{
+		switch(type)
+		{
+		case CT_EDIT:
+			ctrl->style |= ES_LEFT;
+			break;
+		case CT_LISTBOX:
+			ctrl->style |= LBS_NOTIFY;
+			break;
+		case CT_COMBOBOX:
+			ctrl->style |= CBS_SIMPLE | WS_TABSTOP;
+			break;
+		case CT_SCROLLBAR:
+			ctrl->style |= SBS_HORZ;
+			break;
+		case CT_BUTTON:
+			switch(style)
+			{
+			case BS_CHECKBOX:
+			case BS_DEFPUSHBUTTON:
+			case BS_PUSHBUTTON:
+			case BS_GROUPBOX:
+/*			case BS_PUSHBOX:	*/
+			case BS_AUTORADIOBUTTON:
+			case BS_AUTO3STATE:
+			case BS_3STATE:
+			case BS_AUTOCHECKBOX:
+				ctrl->style |= WS_TABSTOP;
+				break;
+			default:
+				yywarning("Unknown default button control-style 0x%08x", style);
+			case BS_RADIOBUTTON:
+				break;
+			}
+			break;
+
+		case CT_STATIC:
+			switch(style)
+			{
+			case SS_LEFT:
+			case SS_RIGHT:
+			case SS_CENTER:
+				ctrl->style |= WS_GROUP;
+				break;
+			case SS_ICON:	/* Special case */
+				break;
+			default:
+				yywarning("Unknown default static control-style 0x%08x", style);
+				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 */
+	if(type == CT_STATIC && style == SS_ICON)
+		ctrl->style |= SS_ICON;
+
+	ctrl->gotstyle = TRUE;
+byebye:
+	return ctrl;
+}
+
+name_id_t *convert_ctlclass(name_id_t *cls)
+{
+	char *cc;
+	int iclass;
+
+	if(cls->type == name_ord)
+		return cls;
+	assert(cls->type == name_str);
+	if(cls->type == str_unicode)
+	{
+		yyerror("Don't yet support unicode class comparison");
+	}
+	else
+		cc = cls->name.s_name->str.cstr;
+
+	if(!stricmp("BUTTON", cc))
+		iclass = CT_BUTTON;
+	else if(!stricmp("COMBOBOX", cc))
+		iclass = CT_COMBOBOX;
+	else if(!stricmp("LISTBOX", cc))
+		iclass = CT_LISTBOX;
+	else if(!stricmp("EDIT", cc))
+		iclass = CT_EDIT;
+	else if(!stricmp("STATIC", cc))
+		iclass = CT_STATIC;
+	else if(!stricmp("SCROLLBAR", cc))
+		iclass = CT_SCROLLBAR;
+	else
+		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;
+}
+
+/* DialogEx specific functions */
+dialogex_t *dialogex_style(int st, dialogex_t *dlg)
+{
+	DWORD s = 0;
+	assert(dlg != NULL);
+	if(dlg->gotstyle)
+	{
+		yywarning("Style already defined, or-ing together");
+		s = dlg->style;
+	}
+	dlg->style = st | s;
+	dlg->gotstyle = TRUE;
+	return dlg;
+}
+
+dialogex_t *dialogex_exstyle(int st, dialogex_t *dlg)
+{
+	DWORD s = 0;
+	assert(dlg != NULL);
+	if(dlg->gotexstyle)
+	{
+		yywarning("ExStyle already defined, or-ing together");
+		s = dlg->exstyle;
+	}
+	dlg->exstyle = st | s;
+	dlg->gotexstyle = TRUE;
+	return dlg;
+}
+
+dialogex_t *dialogex_caption(string_t *s, dialogex_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->title)
+		yyerror("Caption already defined");
+	dlg->title = s;
+	return dlg;
+}
+
+dialogex_t *dialogex_font(font_id_t *f, dialogex_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->font)
+		yyerror("Font already defined");
+	dlg->font = f;
+	return dlg;
+}
+
+dialogex_t *dialogex_class(name_id_t *n, dialogex_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->dlgclass)
+		yyerror("Class already defined");
+	dlg->dlgclass = n;
+	return dlg;
+}
+
+dialogex_t *dialogex_menu(name_id_t *m, dialogex_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->menu)
+		yyerror("Menu already defined");
+	dlg->menu = m;
+	return dlg;
+}
+
+dialogex_t *dialogex_language(language_t *l, dialogex_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->lvc.language)
+		yyerror("Language already defined");
+	dlg->lvc.language = l;
+	return dlg;
+}
+
+dialogex_t *dialogex_characteristics(characts_t *c, dialogex_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->lvc.characts)
+		yyerror("Characteristics already defined");
+	dlg->lvc.characts = c;
+	return dlg;
+}
+
+dialogex_t *dialogex_version(version_t *v, dialogex_t *dlg)
+{
+	assert(dlg != NULL);
+	if(dlg->lvc.version)
+		yyerror("Version already defined");
+	dlg->lvc.version = v;
+	return dlg;
+}
+
+/* Accelerator specific functions */
+event_t *add_event(int key, int id, int flags, event_t *prev)
+{
+	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;
+}
+
+event_t *add_string_event(string_t *key, int id, int flags, event_t *prev)
+{
+	int keycode;
+	event_t *ev = new_event();
+
+	if(key->type != str_char)
+		yyerror("Key code must be an ascii string");
+
+	if((flags & WRC_AF_VIRTKEY) && (!isupper(key->str.cstr[0]) || !isdigit(key->str.cstr[0])))
+		yyerror("VIRTKEY code is not equal to ascii value");
+
+	if(key->str.cstr[0] == '^')
+	{
+		keycode = toupper(key->str.cstr[1]) - '@';
+		if(keycode >= ' ')
+			yyerror("Control-code out of range");
+	}
+	else
+		keycode = key->str.cstr[0];
+	ev->key = keycode;
+	ev->id = id;
+	ev->flags = flags & ~WRC_AF_ASCII;
+	ev->prev = prev;
+	if(prev)
+		prev->next = ev;
+	return ev;
+}
+
+/* MenuEx specific functions */
+itemex_opt_t *new_itemex_opt(int id, int type, int state, int helpid)
+{
+	itemex_opt_t *opt = (itemex_opt_t *)xmalloc(sizeof(itemex_opt_t));
+	opt->id = id;
+	opt->type = type;
+	opt->state = state;
+	opt->helpid = helpid;
+	return opt;
+}
+
+/* Raw data functions */
+raw_data_t *load_file(string_t *name)
+{
+	FILE *fp;
+	raw_data_t *rd;
+	if(name->type != str_char)
+		yyerror("Filename must be ASCII string");
+		
+	fp = fopen(name->str.cstr, "rb");
+	if(!fp)
+		yyerror("Cannot open file %s", name);
+	rd = new_raw_data();
+	fseek(fp, 0, SEEK_END);
+	rd->size = ftell(fp);
+	fseek(fp, 0, SEEK_SET);
+	rd->data = (char *)xmalloc(rd->size);
+	fread(rd->data, rd->size, 1, fp);
+	fclose(fp);
+	HEAPCHECK();
+	return rd;
+}
+
+raw_data_t *int2raw_data(int i)
+{
+	raw_data_t *rd;
+	rd = new_raw_data();
+	rd->size = sizeof(short);
+	rd->data = (char *)xmalloc(rd->size);
+	*(short *)(rd->data) = (short)i;
+	return rd;
+}
+
+raw_data_t *str2raw_data(string_t *str)
+{
+	raw_data_t *rd;
+	rd = new_raw_data();
+	rd->size = str->size * (str->type == str_char ? 1 : 2);
+	rd->data = (char *)xmalloc(rd->size);
+	memcpy(rd->data, str->str.cstr, rd->size);
+	return rd;
+}
+
+raw_data_t *merge_raw_data(raw_data_t *r1, raw_data_t *r2)
+{
+	r1->data = xrealloc(r1->data, r1->size + r2->size);
+	memcpy(r1->data + r1->size, r2->data, r2->size);
+	r1->size += r2->size;
+	return r1;
+}
+
+raw_data_t *merge_raw_data_int(raw_data_t *r1, int i)
+{
+	raw_data_t *t = int2raw_data(i);
+	merge_raw_data(r1, t);
+	free(t->data);
+	free(t);
+	return r1;
+}
+
+raw_data_t *merge_raw_data_str(raw_data_t *r1, string_t *str)
+{
+	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 */
+menu_item_t *get_item_head(menu_item_t *p)
+{
+	if(!p)
+		return NULL;
+	while(p->prev)
+		p = p->prev;
+	return p;
+}
+
+menuex_item_t *get_itemex_head(menuex_item_t *p)
+{
+	if(!p)
+		return NULL;
+	while(p->prev)
+		p = p->prev;
+	return p;
+}
+
+resource_t *get_resource_head(resource_t *p)
+{
+	if(!p)
+		return NULL;
+	while(p->prev)
+		p = p->prev;
+	return p;
+}
+
+ver_block_t *get_ver_block_head(ver_block_t *p)
+{
+	if(!p)
+		return NULL;
+	while(p->prev)
+		p = p->prev;
+	return p;
+}
+
+ver_value_t *get_ver_value_head(ver_value_t *p)
+{
+	if(!p)
+		return NULL;
+	while(p->prev)
+		p = p->prev;
+	return p;
+}
+
+control_t *get_control_head(control_t *p)
+{
+	if(!p)
+		return NULL;
+	while(p->prev)
+		p = p->prev;
+	return p;
+}
+
+event_t *get_event_head(event_t *p)
+{
+	if(!p)
+		return NULL;
+	while(p->prev)
+		p = p->prev;
+	return p;
+}
+
+/* Find a stringtable with given language */
+stringtable_t *find_stringtable(lvc_t *lvc)
+{
+	stringtable_t *stt;
+
+	assert(lvc != NULL);
+
+	if(!lvc->language)
+		lvc->language = currentlanguage;
+
+	for(stt = sttres; stt; stt = stt->next)
+	{
+		if(stt->lvc.language->id == lvc->language->id
+		&& stt->lvc.language->id == lvc->language->id)
+		{
+			/* 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))
+				yywarning("Stringtable's versions are not the same, using first definition");
+
+			if((stt->lvc.characts && lvc->characts && *(stt->lvc.characts) != *(lvc->characts))
+			|| (!stt->lvc.characts && lvc->characts)
+			|| (stt->lvc.characts && !lvc->characts))
+				yywarning("Stringtable's characteristics are not the same, using first definition");
+			*/
+			return stt;
+		}
+	}
+	return NULL;
+}
+
+/* qsort sorting function for string table entries */
+#define STE(p)	((stt_entry_t *)(p))
+int sort_stt_entry(const void *e1, const void *e2)
+{
+	return STE(e1)->id - STE(e2)->id;
+}
+#undef STE
+
+resource_t *build_stt_resources(stringtable_t *stthead)
+{
+	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);
+			newstt->entries = (stt_entry_t *)xmalloc(16 * sizeof(stt_entry_t));
+			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)
+			{
+				warning("Stringtable's memory options are not equal (idbase: %d)", newstt->idbase);
+			}
+			/* Check version and characteristics */
+			for(j = 0; j < 16; j++)
+			{
+				if(characts
+				&& newstt->entries[j].characts
+				&& *newstt->entries[j].characts != *characts)
+					warning("Stringtable's characteristics are not the same (idbase: %d)", newstt->idbase);
+				if(version
+				&& newstt->entries[j].version
+				&& *newstt->entries[j].version != *version)
+					warning("Stringtable's versions are not the same (idbase: %d)", newstt->idbase);
+			}
+			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;
+}
+
+/* Cursor and icon splitter functions */
+int alloc_icon_id(void)
+{
+	static int icon_id = 1;
+	return icon_id++;
+}
+
+int alloc_cursor_id(void)
+{
+	static int cursor_id = 1;
+	return cursor_id++;
+}
+
+#define BPTR(base)	((char *)(rd->data + (base)))
+#define WPTR(base)	((WORD *)(rd->data + (base)))
+#define DPTR(base)	((DWORD *)(rd->data + (base)))
+void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico)
+{
+	int cnt;
+	int i;
+	icon_dir_entry_t *ide;
+	icon_t *ico;
+	icon_t *list = NULL;
+
+	/* FIXME: Distinguish between normal and animated icons (RIFF format) */
+	if(WPTR(0)[1] != 1)
+		yyerror("Icon resource data has invalid type id %d", WPTR(0)[1]);
+	cnt = WPTR(0)[2];
+	ide = (icon_dir_entry_t *)&(WPTR(0)[3]);
+	for(i = 0; i < cnt; i++)
+	{
+		ico = new_icon();
+		ico->id = alloc_icon_id();
+		if(ide[i].offset > rd->size
+		|| ide[i].offset + ide[i].ressize > rd->size)
+			yyerror("Icon resource data corrupt");
+		ico->width = ide[i].width;
+		ico->height = ide[i].height;
+		ico->nclr = ide[i].nclr;
+		ico->planes = ide[i].planes;
+		ico->bits = ide[i].bits;
+		if(!ico->planes)
+		{
+			/* Argh! They did not fill out the resdir structure */
+			ico->planes = ((BITMAPINFOHEADER *)BPTR(ide[i].offset))->biPlanes;
+		}
+		if(!ico->bits)
+		{
+			/* Argh! They did not fill out the resdir structure */
+			ico->bits = ((BITMAPINFOHEADER *)BPTR(ide[i].offset))->biBitCount;
+		}
+		ico->data = new_raw_data();
+		copy_raw_data(ico->data, rd, ide[i].offset, ide[i].ressize);
+		if(!list)
+		{
+			list = ico;
+		}
+		else
+		{
+			ico->next = list;
+			list->prev = ico;
+			list = ico;
+		}
+	}
+	icog->iconlist = list;
+	*nico = cnt;
+}
+
+void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur)
+{
+	int cnt;
+	int i;
+	cursor_dir_entry_t *cde;
+	cursor_t *cur;
+	cursor_t *list = NULL;
+
+	/* FIXME: Distinguish between normal and animated cursors (RIFF format)*/
+	if(WPTR(0)[1] != 2)
+		yyerror("Cursor resource data has invalid type id %d", WPTR(0)[1]);
+	cnt = WPTR(0)[2];
+	cde = (cursor_dir_entry_t *)&(WPTR(0)[3]);
+	for(i = 0; i < cnt; i++)
+	{
+		cur = new_cursor();
+		cur->id = alloc_cursor_id();
+		if(cde[i].offset > rd->size
+		|| cde[i].offset + cde[i].ressize > rd->size)
+			yyerror("Cursor resource data corrupt");
+		cur->width = cde[i].width;
+		cur->height = cde[i].height;
+		cur->nclr = cde[i].nclr;
+		/* The next two are to support color cursors */
+		cur->planes = ((BITMAPINFOHEADER *)BPTR(cde[i].offset))->biPlanes;
+		cur->bits = ((BITMAPINFOHEADER *)BPTR(cde[i].offset))->biBitCount;
+		if(!win32 && (cur->planes != 1 || cur->bits != 1))
+			yywarning("Win16 cursor contains colors");
+		cur->xhot = cde[i].xhot;
+		cur->yhot = cde[i].yhot;
+		cur->data = new_raw_data();
+		copy_raw_data(cur->data, rd, cde[i].offset, cde[i].ressize);
+		if(!list)
+		{
+			list = cur;
+		}
+		else
+		{
+			cur->next = list;
+			list->prev = cur;
+			list = cur;
+		}
+	}
+	curg->cursorlist = list;
+	*ncur = cnt;
+}
+
+#undef	BPTR
+#undef	WPTR
+#undef	DPTR
+
+
diff --git a/tools/wrc/preproc.c b/tools/wrc/preproc.c
new file mode 100644
index 0000000..d523bc5
--- /dev/null
+++ b/tools/wrc/preproc.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <config.h>
+#include "wrc.h"
+#include "utils.h"
+#include "preproc.h"
+#include "parser.h"
+
+
+extern void set_pp_ignore(int);	/* From parser.l */
+
+static char *current_define;
+
+#define HASHKEY		2039
+static struct pp_entry *pp_defines[HASHKEY];
+
+#define MAXIFSTACK	64
+static struct if_state ifstack[MAXIFSTACK];
+static int ifstackidx = 0;
+
+#if 0
+void pp_status(void)
+{
+	int i;
+	int sum;
+	int total = 0;
+	struct pp_entry *ppp;
+
+	printf("Defines statistics:\n");
+	for(i = 0; i < HASHKEY; i++)
+	{
+		sum = 0;
+		for(ppp = pp_defines[i]; ppp; ppp = ppp->next)
+			sum++;
+		total += sum;
+		printf("%4d, %3d\n", i, sum);
+	}
+	printf("Total defines: %d\n", total);
+}
+#pragma exit pp_status
+#endif
+
+/* Don't comment on the hash, its primitive but functional... */
+int pp_hash(char *str)
+{
+	int sum = 0;
+	while(*str)
+		sum += *str++;
+	return sum % HASHKEY;
+}
+
+struct pp_entry *pp_lookup(char *ident)
+{
+	int index = pp_hash(ident);
+	struct pp_entry *ppp;
+	for(ppp = pp_defines[index]; ppp; ppp = ppp->next)
+	{
+		if(!strcmp(ident, ppp->ident))
+			return ppp;
+	}
+	return NULL;
+}
+
+void set_define(char *name)
+{
+	current_define = xstrdup(name);
+}
+
+void del_define(char *name)
+{
+	int index;
+	struct pp_entry *ppp;
+
+	if((ppp = pp_lookup(name)) == NULL)
+	{
+		if(pedantic)
+			yywarning("%s was not defined", name);
+		return;
+	}
+
+	index = pp_hash(name);
+	if(pp_defines[index] == ppp)
+	{
+		pp_defines[index] = ppp->next;
+		if(pp_defines[index])
+			pp_defines[index]->prev = NULL;
+	}
+	else
+	{
+		ppp->prev->next = ppp->next;
+		if(ppp->next)
+			ppp->next->prev = ppp->prev;
+	}
+	free(ppp);
+}
+
+void add_define(char *text)
+{
+	int len;
+	char *cptr;
+	int index = pp_hash(current_define);
+	struct pp_entry *ppp;
+	if(pp_lookup(current_define) != NULL)
+	{
+		if(pedantic)
+			yywarning("Redefinition of %s", current_define);
+		del_define(current_define);
+	}
+	ppp = (struct pp_entry *)xmalloc(sizeof(struct pp_entry));
+	ppp->ident = current_define;
+	ppp->subst = xstrdup(text);
+	ppp->next = pp_defines[index];
+	pp_defines[index] = ppp;
+	if(ppp->next)
+		ppp->next->prev = ppp;
+	/* Strip trailing white space from subst text */
+	len = strlen(ppp->subst);
+	while(len && strchr(" \t\r\n", ppp->subst[len-1]))
+	{
+		ppp->subst[--len] = '\0';
+	}
+	/* Strip leading white space from subst text */
+	for(cptr = ppp->subst; *cptr && strchr(" \t\r", *cptr); cptr++)
+		;
+	if(ppp->subst != cptr)
+		memmove(ppp->subst, cptr, strlen(cptr)+1);
+	if(yydebug)
+		printf("Added (%s, %d) <%s> to <%s>\n", input_name, line_number, ppp->ident, ppp->subst);
+}
+
+void add_cmdline_define(char *set)
+{
+	char *cpy = xstrdup(set);	/* Because gcc passes a R/O string */
+	char *cptr = strchr(cpy, '=');
+	if(cptr)
+		*cptr = '\0';
+	set_define(cpy);
+	add_define(cptr ? cptr+1 : "");
+	free(cpy);
+}
+
+#if defined(_Windows) || defined(__MSDOS__)
+#define INCLUDESEPARATOR	";"
+#else
+#define INCLUDESEPARATOR	":"
+#endif
+
+static char **includepath;
+static int nincludepath = 0;
+
+void add_include_path(char *path)
+{
+	char *tok;
+	char *cpy = xstrdup(path);
+
+	tok = strtok(cpy, INCLUDESEPARATOR);
+	while(tok)
+	{
+		char *dir;
+		char *cptr;
+		if(strlen(tok) == 0)
+			continue;
+		dir = xstrdup(tok);
+		for(cptr = dir; *cptr; cptr++)
+		{
+			/* Convert to forward slash */
+			if(*cptr == '\\')
+				*cptr = '/';
+		}
+		/* Kill eventual trailing '/' */
+		if(*(cptr = dir + strlen(dir)-1) == '/')
+			*cptr = '\0';
+
+		/* Add to list */
+		nincludepath++;
+		includepath = (char **)xrealloc(includepath, nincludepath * sizeof(*includepath));
+		includepath[nincludepath-1] = dir;
+		tok = strtok(NULL, INCLUDESEPARATOR);
+	}
+	free(cpy);
+}
+
+FILE *open_include(const char *name, int search)
+{
+	char *cpy = xstrdup(name);
+	char *cptr;
+	FILE *fp;
+	int i;
+
+	for(cptr = cpy; *cptr; cptr++)
+	{
+		/* kill double backslash */
+		if(*cptr == '\\' && *(cptr+1) == '\\')
+			memmove(cptr, cptr+1, strlen(cptr));
+		/* Convert to forward slash */
+		if(*cptr == '\\')
+			*cptr = '/';
+	}
+
+	if(search)
+	{
+		/* Search current dir and then -I path */
+		fp = fopen(name, "rt");
+		if(fp)
+		{
+			if(yydebug)
+				printf("Going to include <%s>\n", name);
+			free(cpy);
+			return fp;
+		}
+	}
+	/* Search -I path */
+	for(i = 0; i < nincludepath; i++)
+	{
+		char *path;
+		path = (char *)xmalloc(strlen(includepath[i]) + strlen(cpy) + 2);
+		strcpy(path, includepath[i]);
+		strcat(path, "/");
+		strcat(path, cpy);
+		fp = fopen(path, "rt");
+		if(fp && yydebug)
+			printf("Going to include <%s>\n", path);
+		free(path);
+		if(fp)
+		{
+			free(cpy);
+			return fp;
+		}
+
+	}
+	free(cpy);
+	return NULL;
+}
+
+void push_if(int truecase, int wastrue, int nevertrue)
+{
+	if(ifstackidx >= MAXIFSTACK-1)
+		internal_error(__FILE__, __LINE__, "#if stack overflow");
+	ifstack[ifstackidx].current = truecase && !wastrue;
+	ifstack[ifstackidx].hasbeentrue = wastrue;
+	ifstack[ifstackidx].nevertrue = nevertrue;
+	if(nevertrue || !(truecase && !wastrue))
+		set_pp_ignore(1);
+	if(yydebug)
+		printf("push_if: %d %d %d (%d %d %d)\n",
+			truecase,
+			wastrue,
+			nevertrue,
+			ifstack[ifstackidx].current,
+			ifstack[ifstackidx].hasbeentrue,
+			ifstack[ifstackidx].nevertrue);
+	ifstackidx++;
+}
+
+int pop_if(void)
+{
+	if(ifstackidx <= 0)
+		yyerror("#endif without #if|#ifdef|#ifndef (#if stack underflow)");
+	ifstackidx--;
+	if(yydebug)
+		printf("pop_if: %d %d %d\n",
+			ifstack[ifstackidx].current,
+			ifstack[ifstackidx].hasbeentrue,
+			ifstack[ifstackidx].nevertrue);
+	if(ifstack[ifstackidx].nevertrue || !ifstack[ifstackidx].current)
+		set_pp_ignore(0);
+	return ifstack[ifstackidx].hasbeentrue || ifstack[ifstackidx].current;
+}
+
+int isnevertrue_if(void)
+{
+	return ifstackidx > 0 && ifstack[ifstackidx-1].nevertrue;
+}
+
diff --git a/tools/wrc/preproc.h b/tools/wrc/preproc.h
new file mode 100644
index 0000000..c8f13f7
--- /dev/null
+++ b/tools/wrc/preproc.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ */
+
+#ifndef __WRC_PREPROC_H
+#define __WRC_PREPROC_H
+
+struct pp_entry {
+	struct pp_entry *next;
+	struct pp_entry *prev;
+	char	*ident;
+	char	*subst;
+	int	expanding;
+};
+
+struct if_state {
+	int	current;
+	int	hasbeentrue;
+	int	nevertrue;
+};
+
+struct pp_entry *pp_lookup(char *ident);
+void set_define(char *name);
+void del_define(char *name);
+void add_define(char *text);
+void add_cmdline_define(char *set);
+FILE *open_include(const char *name, int search);
+void add_include_path(char *path);
+void push_if(int truecase, int wastrue, int nevertrue);
+int pop_if(void);
+int isnevertrue_if(void);
+
+#endif
+
diff --git a/tools/wrc/readres.c b/tools/wrc/readres.c
new file mode 100644
index 0000000..c2fdc6d
--- /dev/null
+++ b/tools/wrc/readres.c
@@ -0,0 +1,369 @@
+/*
+ * Read a .res file and create a resource-tree
+ *
+ * Copyright 1998 Bertho A. Stultiens
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <config.h>
+#include "wrc.h"
+#include "readres.h"
+#include "newstruc.h"
+#include "utils.h"
+#include "genres.h"
+
+struct resheader32 {
+	DWORD	ressize;	/* 0 */
+	DWORD	hdrsize;	/* 0x20 */
+	WORD	restype1;	/* 0xffff */
+	WORD	restype2;	/* 0 */
+	WORD	resname1;	/* 0xffff */
+	WORD	resname2;	/* 0 */
+	DWORD	dversion;	/* 0 */
+	WORD	memopt;		/* 0 */
+	WORD	language;	/* 0 */
+	DWORD	version;	/* 0 */
+	DWORD	characts;	/* 0 */
+} emptyheader = {0, 0x20, 0xffff, 0, 0xffff, 0, 0, 0, 0, 0, 0};
+
+/*
+ *****************************************************************************
+ * Function	:
+ * Syntax	:
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+/*
+ *****************************************************************************
+ * Function	:
+ * Syntax	:
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+/*
+ *****************************************************************************
+ * Function	:
+ * Syntax	:
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+int read_data(FILE *fp, size_t size, void *buf)
+{
+	int r;
+	int pos = ftell(fp);
+	r = fread(buf, 1, size, fp);
+	if(r == size)
+		return 0;
+	if(r == 0 && ftell(fp) - pos > 0)
+		return 1;
+	else
+		return -1;
+}
+
+/*
+ *****************************************************************************
+ * Function	:
+ * Syntax	:
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+enum res_e res_type_from_id(name_id_t *nid)
+{
+	if(nid->type == name_str)
+		return res_usr;
+
+	if(nid->type != name_ord)
+		internal_error(__FILE__, __LINE__, "Invalid name_id descriptor %d", nid->type);
+
+	switch(nid->name.i_name)
+	{
+	case WRC_RT_CURSOR:		return res_cur;
+	case WRC_RT_BITMAP:		return res_bmp;
+	case WRC_RT_ICON:		return res_ico;
+	case WRC_RT_MENU:		return res_men;
+	case WRC_RT_DIALOG:		return res_dlg;
+	case WRC_RT_STRING:		return res_stt;
+	case WRC_RT_FONTDIR:		return res_fntdir;
+	case WRC_RT_FONT:		return res_fnt;
+	case WRC_RT_ACCELERATOR:	return res_acc;
+	case WRC_RT_RCDATA:		return res_rdt;
+	case WRC_RT_MESSAGETABLE:	return res_msg;
+	case WRC_RT_GROUP_CURSOR:	return res_curg;
+	case WRC_RT_GROUP_ICON:		return res_icog;
+	case WRC_RT_VERSION:		return res_ver;
+
+	default:
+	case WRC_RT_DLGINCLUDE:
+	case WRC_RT_PLUGPLAY:
+	case WRC_RT_VXD:
+	case WRC_RT_ANICURSOR:
+	case WRC_RT_ANIICON:
+		warning("Cannot be sure of resource type, using usertype settings");
+		return res_usr;
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	:
+ * Syntax	:
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+#define get_word(idx)	(*((WORD *)(&res->data[idx])))
+#define get_dword(idx)	(*((DWORD *)(&res->data[idx])))
+
+resource_t *read_res32(FILE *fp)
+{
+	static char wrong_format[] = "Wrong resfile format (32bit)";
+	DWORD ressize;
+	DWORD hdrsize;
+	DWORD totsize;
+	WORD memopt;
+	WORD language;
+	int err;
+	res_t *res;
+	resource_t *rsc;
+	resource_t *tail = NULL;
+	resource_t *list = NULL;
+	name_id_t *type = NULL;
+	name_id_t *name = NULL;
+	int idx;
+	enum res_e res_type;
+	user_t *usrres;
+
+	while(1)
+	{
+		/* Get headersize and resource size */
+		err = read_data(fp, sizeof(ressize), &ressize);
+		if(err < 0)
+			break;
+		else if(err > 0)
+			error(wrong_format);
+		err = read_data(fp, sizeof(hdrsize), &hdrsize);
+		if(err)
+			error(wrong_format);
+
+		/* Align sizes and compute total size */
+		totsize = hdrsize;
+		if(hdrsize & 3)
+		{
+			warning("Hu? .res header needed alignment (anything can happen now)");
+			totsize += 4 - (hdrsize & 3);
+		}
+		totsize += ressize;
+		if(ressize & 3)
+			totsize += 4 - (ressize & 3);
+
+		/* Read in entire data-block */
+		fseek(fp, -8, SEEK_CUR);
+		res = new_res();
+		if(res->allocsize < totsize)
+			grow_res(res, totsize - res->allocsize + 8);
+		err = read_data(fp, totsize, res->data);
+		if(err)
+			error(wrong_format);
+
+		res->dataidx = hdrsize;
+		res->size = hdrsize + ressize;
+
+		/* Analyse the content of the header */
+		idx = 8;
+		/* Get restype */
+		if(get_word(idx) == 0xffff)
+		{
+			idx += sizeof(WORD);
+			type = new_name_id();
+			type->type = name_ord;
+			type->name.i_name = get_word(idx);
+			idx += sizeof(WORD);
+		}
+		else if(get_word(idx) == 0)
+		{
+			error("ResType name has zero length (32 bit)");
+		}
+		else
+		{
+			int tag = idx;
+			string_t *str;
+			while(1)
+			{
+				idx += sizeof(WORD);
+				if(!get_word(idx))
+					break;
+			}
+			idx += sizeof(WORD);
+			str = new_string();
+			str->type = str_unicode;
+			str->size = (idx - tag) / 2;
+			str->str.wstr = (short *)xmalloc(idx-tag+2);
+			memcpy(str->str.wstr, &res->data[tag], idx-tag);
+			str->str.wstr[str->size] = 0;
+			type = new_name_id();
+			type->type = name_str;
+			type->name.s_name = str;
+		}
+		/* Get resname */
+		if(get_word(idx) == 0xffff)
+		{
+			idx += sizeof(WORD);
+			name = new_name_id();
+			name->type = name_ord;
+			name->name.i_name = get_word(idx);
+			idx += sizeof(WORD);
+		}
+		else if(get_word(idx) == 0)
+		{
+			error("ResName name has zero length (32 bit)");
+		}
+		else
+		{
+			int tag = idx;
+			string_t *str;
+			while(1)
+			{
+				idx += sizeof(WORD);
+				if(!get_word(idx))
+					break;
+			}
+			idx += sizeof(WORD);
+			str = new_string();
+			str->type = str_unicode;
+			str->size = (idx - tag) / 2;
+			str->str.wstr = (short *)xmalloc(idx-tag+2);
+			memcpy(str->str.wstr, &res->data[tag], idx-tag);
+			str->str.wstr[str->size] = 0;
+			name = new_name_id();
+			name->type = name_str;
+			name->name.s_name = str;
+		}
+
+		/* align */
+		if(idx & 0x3)
+			idx += 4 - (idx & 3);
+
+		idx += sizeof(DWORD);	/* Skip DataVersion */
+		memopt = get_word(idx);
+		idx += sizeof(WORD);
+		language = get_word(idx);
+
+		/* Build a resource_t list */
+		res_type = res_type_from_id(type);
+		if(res_type == res_usr)
+		{
+			/* User-type has custom ResType for .[s|h] generation */
+			usrres = new_user(type, NULL, new_int(memopt));
+		}
+		else
+			usrres = NULL;
+		rsc = new_resource(res_type,
+				   usrres,
+				   memopt,
+				   new_language(PRIMARYLANGID(language),
+						SUBLANGID(language)));
+		rsc->binres = res;
+		rsc->name = name;
+		rsc->c_name = make_c_name(get_c_typename(res_type), name, rsc->lan);
+		if(!list)
+		{
+			list = rsc;
+			tail = rsc;
+		}
+		else
+		{
+			rsc->prev = tail;
+			tail->next = rsc;
+			tail = rsc;
+		}
+	}
+	return list;
+}
+
+/*
+ *****************************************************************************
+ * Function	:
+ * Syntax	:
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+resource_t *read_res16(FILE *fp)
+{
+	internal_error(__FILE__, __LINE__, "Can't yet read 16 bit .res files");
+	return NULL;
+}
+
+/*
+ *****************************************************************************
+ * Function	: read_resfile
+ * Syntax	: resource_t *read_resfile(char *inname)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+resource_t *read_resfile(char *inname)
+{
+	FILE *fp;
+	struct resheader32 rh;
+	int is32bit;
+	resource_t *top;
+
+	fp = fopen(inname, "rb");
+	if(!fp)
+		error("Could not open inputfile %s", inname);
+
+	/* Determine 16 or 32 bit .res file */
+	if(fread(&rh, 1, sizeof(rh), fp) != sizeof(rh))
+		is32bit = 0;
+	else
+	{
+		if(!memcmp(&emptyheader, &rh, sizeof(rh)))
+			is32bit = 1;
+		else
+			is32bit = 0;
+	}
+
+	if(is32bit && !win32)
+		error("Cannot convert 32-bit .res-file into 16-bit resources (and will, hopefully never, implement it)");
+
+	if(!is32bit && win32)
+		error("Cannot (yet) convert 16-bit .res-file into 32-bit resources");
+
+	if(!is32bit)
+	{
+		fseek(fp, 0, SEEK_SET);
+		top = read_res16(fp);
+	}
+	else
+	{
+		top = read_res32(fp);
+	}
+
+	fclose(fp);
+
+	return top;
+}
diff --git a/tools/wrc/readres.h b/tools/wrc/readres.h
new file mode 100644
index 0000000..e87da51
--- /dev/null
+++ b/tools/wrc/readres.h
@@ -0,0 +1,17 @@
+/*
+ * Read binary resource prototypes
+ *
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ */
+
+#ifndef __WRC_READRES_H
+#define __WRC_READRES_H
+
+#ifndef __WRC_WRCTYPES_H
+#include "wrctypes.h"
+#endif
+
+resource_t *read_resfile(char *inname);
+
+#endif
diff --git a/tools/wrc/utils.c b/tools/wrc/utils.c
new file mode 100644
index 0000000..fd2832f
--- /dev/null
+++ b/tools/wrc/utils.c
Binary files differ
diff --git a/tools/wrc/utils.h b/tools/wrc/utils.h
new file mode 100644
index 0000000..e16613a
--- /dev/null
+++ b/tools/wrc/utils.h
@@ -0,0 +1,40 @@
+/*
+ * Utility routines' prototypes etc.
+ *
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ */
+
+#ifndef __WRC_UTILS_H
+#define __WRC_UTILS_H
+
+#ifndef __WRC_WRCTYPES_H
+#include "wrctypes.h"
+#endif
+
+#include <stddef.h>	/* size_t */
+
+void *xmalloc(size_t);
+void *xrealloc(void *, size_t);
+char *xstrdup(const char *str);
+
+int yyerror(const char *s, ...);
+int yywarning(const char *s, ...);
+void internal_error(const char *file, int line, const char *s, ...);
+void error(const char *s, ...);
+void warning(const char *s, ...);
+void chat(const char *s, ...);
+
+char *dup_basename(const char *name, const char *ext);
+int string_compare(const string_t *s1, const string_t *s2);
+int wstrlen(const short *s);
+short *wstrcpy(short *dst, const short *src);
+int wstricmp(const short *s1, const short *s2);
+char *dupwstr2cstr(const short *str);
+short *dupcstr2wstr(const char *str);
+
+#ifndef HAVE_STRICMP
+int stricmp(const char *s1, const char *s2);
+#endif
+
+#endif
diff --git a/tools/wrc/wrc.c b/tools/wrc/wrc.c
new file mode 100644
index 0000000..910cf14
--- /dev/null
+++ b/tools/wrc/wrc.c
@@ -0,0 +1,492 @@
+/*
+ *
+ * Copyright  Martin von Loewis, 1994
+ * Copyrignt 1998 Bertho A. Stultiens (BS)
+ *
+ * 21-May-1998 BS	- Removed the CPP option. Its internal now.
+ *			- Added implementations for defines and includes
+ *			  on the commandline.
+ *
+ * 30-Apr-1998 BS	- The options now contain nearly the entire alphabet.
+ *			  Seems to be a sign for too much freedom. I implemeted
+ *			  most of them as a user choice possibility for things
+ *			  that I do not know what to put there by default.
+ *			- -l and -L options are now known as -t and -T.
+ *
+ * 23-Apr-1998 BS	- Finally gave up on backward compatibility on the
+ *			  commandline (after a blessing from the newsgroup).
+ *			  So, I changed the lot.
+ *
+ * 17-Apr-1998 BS	- Added many new command-line options but took care
+ *			  that it would not break old scripts (sigh).
+ *
+ * 16-Apr-1998 BS	- There is not much left of the original source...
+ *			  I had to rewrite most of it because the parser
+ *			  changed completely with all the types etc..
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include <config.h>
+#include "wrc.h"
+#include "utils.h"
+#include "writeres.h"
+#include "readres.h"
+#include "dumpres.h"
+#include "genres.h"
+#include "newstruc.h"
+#include "preproc.h"
+#include "parser.h"
+
+char usage[] = "Usage: wrc [options...] [infile[.rc|.res]]\n"
+	"   -a n        Alignment of resource (win16 only, default is 4)\n"
+	"   -b          Create a C array from a binary .res file\n"
+	"   -c          Add 'const' prefix to C constants\n"
+	"   -C cp       Set the resource's codepage to cp (default is 0)\n"
+	"   -d n        Set debug level to 'n'\n"
+	"   -D id[=val] Define preprocessor identifier id=val\n"
+	"   -e          Disable recognition of win32 keywords in 16bit compile\n"
+	"   -g          Add symbols to the global c namespace\n"
+	"   -h          Also generate a .h file\n"
+	"   -H file     Same as -h but written to file\n"
+	"   -I path     Set include search dir to path (multiple -I allowed)\n"
+	"   -l lan      Set default language to lan (default is neutral {0})\n"
+	"   -n          Do not generate .s file\n"
+	"   -o file     Output to file (default is infile.[res|s|h]\n"
+	"   -p prefix   Give a prefix for the generated names\n"
+	"   -r          Create binary .res file (compile only)\n"
+	"   -s          Add structure with win32/16 (PE/NE) resource directory\n"
+	"   -t          Generate indirect loadable resource tables\n"
+	"   -T          Generate only indirect loadable resources tables\n"
+	"   -V          Print version end exit\n"
+	"   -w 16|32    Select win16 or win32 output (default is win32)\n"
+	"   -W          Enable pedantic warnings\n"
+	"Input is taken from stdin if no sourcefile specified.\n"
+	"Debug level 'n' is a bitmask with following meaning:\n"
+	"    * 0x01 Tell which resource is parsed (verbose mode)\n"
+	"    * 0x02 Dump internal structures\n"
+	"    * 0x04 Create a parser trace (yydebug=1)\n"
+	"The -o option only applies to the final destination file, which is\n"
+	"in case of normal compile a .s file. You must use the '-H header.h'\n"
+	"option to override the header-filename.\n"
+	"If no input filename is given and the output name is not overridden\n"
+	"with -o and/or -H, then the output is written to \"wrc.tab.[sh]\"\n"
+	;
+
+char version_string[] = "Wine Resource Compiler Version " WRC_FULLVERSION "\n"
+			"Copyright 1998 Bertho A. Stultiens\n"
+			"          1994 Martin von Loewis\n";
+
+/*
+ * Default prefix for resource names used in the C array.
+ * Option '-p name' sets it to 'name'
+ */
+char *prefix = "_Resource";
+
+/*
+ * Set if compiling in 32bit mode (default).
+ */
+int win32 = 1;
+
+/*
+ * Set when generated C variables should be prefixed with 'const'
+ */
+int constant = 0;
+
+/*
+ * Create a .res file from the source and exit (-r option).
+ * The compiler actually always creates this file, and then
+ * converts it into whatever is requested. The compiler just
+ * stops after the res-file when create_res is set.
+ */
+int create_res = 0;
+
+/*
+ * debuglevel == DEBUGLEVEL_NONE	Don't bother
+ * debuglevel & DEBUGLEVEL_CHAT		Say whats done
+ * debuglevel & DEBUGLEVEL_DUMP		Dump internal structures
+ * debuglevel & DEBUGLEVEL_TRACE	Create parser trace
+ */
+int debuglevel = DEBUGLEVEL_NONE;
+
+/*
+ * Recognize win32 keywords if set (-w 32 enforces this),
+ * otherwise set with -e option.
+ */
+int extensions = 1;
+
+/*
+ * Set when creating C array from .res file (-b option).
+ */
+int binary = 0;
+
+/*
+ * Set when an additional C-header is to be created in compile (-h option).
+ */
+int create_header = 0;
+
+/*
+ * Set when the NE/PE resource directory should be dumped into
+ * the output file.
+ */
+int create_dir = 0;
+
+/*
+ * Set when all symbols should be added to the global namespace (-g option)
+ */
+int global = 0;
+
+/*
+ * Set when indirect loadable resource tables should be created (-t)
+ */
+int indirect = 0;
+
+/*
+ * Set when _only_ indirect loadable resource tables should be created (-T)
+ */
+int indirect_only = 0;
+
+/*
+ * NE segment resource aligment (-a option)
+ */
+int alignment = 4;
+int alignment_pwr;
+
+/*
+ * Cleared when the assembly file must be suppressed (-n option)
+ */
+int create_s = 1;
+
+/*
+ * Language setting for resources (-l option)
+ */
+language_t *currentlanguage = NULL;
+
+/*
+ * The codepage to write in win32 PE resource segment (-C option)
+ */
+DWORD codepage = 0;
+
+/*
+ * Set when extra warnings should be generated (-W option)
+ */
+int pedantic = 0;
+
+char *output_name;		/* The name given by the -o option */
+char *input_name;		/* The name given on the command-line */
+char *header_name;		/* The name given by the -H option */
+
+char *cmdline;			/* The entire commandline */
+
+resource_t *resource_top;	/* The top of the parsed resources */
+
+int getopt (int argc, char *const *argv, const char *optstring);
+
+int main(int argc,char *argv[])
+{
+	extern char* optarg;
+	extern int   optind;
+	int optc;
+	int lose = 0;
+	int ret;
+	int a;
+	int i;
+	int cmdlen;
+
+	/* First rebuild the commandline to put in destination */
+	/* Could be done through env[], but not all OS-es support it */
+	cmdlen = 4; /* for "wrc " */
+	for(i = 1; i < argc; i++)
+		cmdlen += strlen(argv[i]) + 1;
+	cmdline = (char *)xmalloc(cmdlen);
+	strcpy(cmdline, "wrc ");
+	for(i = 1; i < argc; i++)
+	{
+		strcat(cmdline, argv[i]);
+		if(i < argc-1)
+			strcat(cmdline, " ");
+	}
+
+	while((optc = getopt(argc, argv, "a:bcC:d:D:eghH:I:l:no:p:rstTVw:W")) != EOF)
+	{
+		switch(optc)
+		{
+		case 'a':
+			alignment = atoi(optarg);
+			break;
+		case 'b':
+			binary = 1;
+			break;
+		case 'c':
+			constant = 1;
+			break;
+		case 'C':
+			codepage = strtol(optarg, NULL, 0);
+			break;
+		case 'd':
+			debuglevel = strtol(optarg, NULL, 0);
+			break;
+		case 'D':
+			add_cmdline_define(optarg);
+			break;
+		case 'e':
+			extensions = 0;
+			break;
+		case 'g':
+			global = 1;
+			break;
+		case 'H':
+			header_name = strdup(optarg);
+			/* Fall through */
+		case 'h':
+			create_header = 1;
+			break;
+		case 'I':
+			add_include_path(optarg);
+			break;
+		case 'l':
+			{
+				int lan;
+				lan = strtol(optarg, NULL, 0);
+				currentlanguage = new_language(PRIMARYLANGID(lan), SUBLANGID(lan));
+			}
+			break;
+		case 'n':
+			create_s = 0;
+			break;
+		case 'o':
+			output_name = strdup(optarg);
+			break;
+		case 'p':
+			prefix = strdup(optarg);
+			break;
+		case 'r':
+			create_res = 1;
+			break;
+		case 's':
+			create_dir = 1;
+			break;
+		case 'T':
+			indirect_only = 1;
+			/* Fall through */
+		case 't':
+			indirect = 1;
+			break;
+		case 'V':
+			printf(version_string);
+			exit(0);
+			break;
+		case 'w':
+			if(!strcmp(optarg, "16"))
+				win32 = 0;
+			else if(!strcmp(optarg, "32"))
+				win32 = 1;
+			else
+				lose++;
+			break;
+		case 'W':
+			pedantic = 1;
+			break;
+		default:
+			lose++;
+			break;
+		}
+	}
+
+	if(lose)
+	{
+		fprintf(stderr, usage);
+		return 1;
+	}
+
+	/* Check the command line options for invalid combinations */
+	if(win32)
+	{
+		if(!extensions)
+		{
+			warning("Option -e ignored with 32bit compile\n");
+			extensions = 1;
+		}
+	}
+
+	if(create_res)
+	{
+		if(constant)
+		{
+			warning("Option -c ignored with compile to .res\n");
+			constant = 0;
+		}
+
+		if(create_header)
+		{
+			warning("Option -[h|H] ignored with compile to .res\n");
+			create_header = 0;
+		}
+
+		if(indirect)
+		{
+			warning("Option -l ignored with compile to .res\n");
+			indirect = 0;
+		}
+
+		if(indirect_only)
+		{
+			warning("Option -L ignored with compile to .res\n");
+			indirect_only = 0;
+		}
+
+		if(global)
+		{
+			warning("Option -g ignored with compile to .res\n");
+			global = 0;
+		}
+
+		if(create_dir)
+		{
+			error("Option -r and -s cannot be used together\n");
+		}
+
+		if(binary)
+		{
+			error("Option -r and -b cannot be used together\n");
+		}
+	}
+
+	/* Set alignment power */
+	a = alignment;
+	for(alignment_pwr = 0; alignment_pwr < 10 && a > 1; alignment_pwr++)
+	{
+		a >>= 1;
+	}
+	if(a != 1)
+	{
+		error("Alignment must be between 1 and 1024");
+	}
+	if((1 << alignment_pwr) != alignment)
+	{
+		error("Alignment must be a power of 2");
+	}
+
+	/* Kill io buffering when some kind of debuglevel is enabled */
+	if(debuglevel)
+	{
+		setbuf(stdout,0);
+		setbuf(stderr,0);
+	}
+
+	yydebug = debuglevel & DEBUGLEVEL_TRACE ? 1 : 0;
+
+	/* Set the default defined stuff */
+	add_cmdline_define("RC_INVOKED=1");
+	add_cmdline_define("__WRC__=1");
+	if(win32)
+	{
+		add_cmdline_define("__WIN32__=1");
+		add_cmdline_define("__FLAT__=1");
+	}
+
+	/* Check if the user set a language, else set default */
+	if(!currentlanguage)
+		currentlanguage = new_language(0, 0);
+
+	/* Check for input file on command-line */
+	if(optind < argc)
+	{
+		input_name = argv[optind];
+		yyin = fopen(input_name, "rb");
+		if(!yyin)
+		{
+			error("Could not open %s\n", input_name);
+		}
+	}
+	else
+	{
+		yyin = stdin;
+	}
+
+	if(binary && !input_name)
+	{
+		error("Binary mode requires .res file as input");
+	}
+
+	if(!output_name)
+	{
+		output_name = dup_basename(input_name, binary ? ".res" : ".rc");
+		strcat(output_name, create_res ? ".res" : ".s");
+	}
+
+	if(!header_name && !create_res)
+	{
+		header_name = dup_basename(input_name, binary ? ".res" : ".rc");
+		strcat(header_name, ".h");
+	}
+
+	if(!binary)
+	{
+		/* Go from .rc to .res or .s */
+		chat("Starting parse");
+		ret = yyparse();
+
+		if(input_name)
+			fclose(yyin);
+
+		if(ret)
+		{
+			/* Error during parse */
+			exit(1);
+		}
+
+		if(debuglevel & DEBUGLEVEL_DUMP)
+			dump_resources(resource_top);
+
+		/* Convert the internal lists to binary data */
+		resources2res(resource_top);
+
+		if(create_res)
+		{
+			chat("Writing .res-file");
+			write_resfile(output_name, resource_top);
+		}
+		else
+		{
+			if(create_s)
+			{
+				chat("Writing .s-file");
+				write_s_file(output_name, resource_top);
+			}
+			if(create_header)
+			{
+				chat("Writing .h-file");
+				write_h_file(header_name, resource_top);
+			}
+		}
+
+	}
+	else
+	{
+		/* Go from .res to .s */
+		chat("Reading .res-file");
+		resource_top = read_resfile(input_name);
+		if(create_s)
+		{
+			chat("Writing .s-file");
+			write_s_file(output_name, resource_top);
+		}
+		if(create_header)
+		{
+			chat("Writing .h-file");
+			write_h_file(header_name, resource_top);
+		}
+	}
+
+	return 0;
+}
+
+
+
+
diff --git a/tools/wrc/wrc.doc b/tools/wrc/wrc.doc
new file mode 100644
index 0000000..94846aa
--- /dev/null
+++ b/tools/wrc/wrc.doc
@@ -0,0 +1,174 @@
+
+
+/*****************************************************************************\
+ * Win32 Resource files grammar:
+ *
+ * Top level keywords/resource items:
+ *	nameID ACCELERATOR
+ *	[CHARACTERISTICS dword]
+ *	[LANGUAGE language, sublanguage]
+ *	[VERSION dword]
+ *	BEGIN
+ *		event, IDvalue [, type] [options]
+ *		...
+ *	END
+ *-------------
+ *	nameID BITMAP [loadmem] filename
+ *-------------
+ *	nameID BITMAP [loadmem]
+ *	BEGIN
+ *		rawdata
+ *	END
+ *-------------
+ *	nameID CURSOR [loadmem] filename
+ *-------------
+ *	nameID CURSOR [loadmem]
+ *	BEGIN
+ *		rawdata
+ *	END
+ *-------------
+ *	nameID DIALOG [loadmem] [EXSTYLE=extended-styles] x, y, width, height
+ *	[CAPTION "text"]
+ *	[CHARACTERISTICS dword]
+ *	[CLASS class]
+ *	[EXSTYLE=extended-styles]
+ *	[FONT pointsize, face]
+ *	[LANGUAGE language, sublanguage]
+ *	[MENU menuname]
+ *	[STYLE styles]
+ *	[VERSION dword]
+ *	BEGIN
+ *		[controls]
+ *	END
+ *-------------
+ *	nameID DIALOGEX [loadmem] x, y, width, height [, helpID]
+ *	[CAPTION "text"]
+ *	[CHARACTERISTICS dword]
+ *	[CLASS class]
+ *	[EXSTYLE=extended-styles]
+ *	[FONT pointsize, face, weight, italic]
+ *	[LANGUAGE language, sublanguage]
+ *	[MENU menuname]
+ *	[STYLE styles]
+ *	[VERSION dword]
+ *	BEGIN
+ *		[controls]
+ *	END
+ *-------------
+ *	nameID FONT [loadmem] filename
+ *-------------
+ *	nameID ICON [loadmem] filename
+ *-------------
+ *	nameID ICON [loadmem]
+ *	BEGIN
+ *		rawdata
+ *	END
+ *-------------
+ *	LANGUAGE languageID, sublanguageID
+ *-------------
+ *	nameID MENU [loadmem]
+ *	[CHARACTERISTICS dword]
+ *	[LANGUAGE language, sublanguage]
+ *	[VERSION dword]
+ *	BEGIN
+ *		[menuitems]
+ *	END
+ *-------------
+ *	nameID MENUEX [loadmem]
+ *	[CHARACTERISTICS dword]
+ *	[LANGUAGE language, sublanguage]
+ *	[VERSION dword]
+ *	BEGIN
+ *		[menuexitems]
+ *	END
+ *-------------
+ *	nameID MESSAGETABLE [loadmem] filename
+ *-------------
+ *	nameID RCDATA [loadmem]
+ *	[CHARACTERISTICS dword]
+ *	[LANGUAGE language, sublanguage]
+ *	[VERSION dword]
+ *	BEGIN
+ *		[raw-data]
+ *	END
+ *-------------
+ *	STRINGTABLE [loadmem]
+ *	[CHARACTERISTICS dword]
+ *	[LANGUAGE language, sublanguage]
+ *	[VERSION dword]
+ *	BEGIN
+ *		[stringID, "text"]
+ *		...
+ *	END
+ *-------------
+ *	versionID VERSIONINFO
+ *	FILEVERSION	maj1, maj2, min1, min2
+ *	PRODUCTVERSION	maj1, maj2, min1, min2
+ *	FILEFLAGSMASK	(VS_FFI_FILEFLAGMASK)
+ *	FILEOS		(VOS_*)
+ *	FILETYPE	(VFT_*)
+ *	FILEFLAGS	(VS_FF_*)
+ *	FILESUBTYPE	(VFT2_*)
+ *	BEGIN
+ *		BLOCK "StringFileInfo"
+ *		BEGIN
+ *			BLOCK "language-charset"
+ *			BEGIN
+ *				[VALUE "Comments", "yep\0"]
+ *				VALUE "CompanyName", "Wine Developer Team\0"
+ *				VALUE "FileDescription", "Resource compiler\0"
+ *				VALUE "FileVersion", "0.01 alpha\0"
+ *				VALUE "InternalName", "winerc\0"
+ *				[VALUE "LegalCopyright", "Copyright (c) B.A. Stultiens 1998\0"]
+ *				[VALUE "LegalTrademarks", "...\0"]
+ *				VALUE "OriginalFilename", "winerc\0"
+ *				[VALUE "PrivateBuild", "Yes always!\0"
+ *				VALUE "ProductName", "Wine\0"
+ *				VALUE "ProductVersion", "0.01 alpha\0"
+ *				[VALUE "SpecialBuild", "No never! Well, maybe.\0"
+ *			END
+ *		END
+ *		BLOCK "VarFileInfo"
+ *		BEGIN
+ *			VALUE "Translation", languageID, charsetID
+ *		END
+ *	END
+ *-------------
+ *	nameID typeID [loadmem] filename
+ *-------------
+ *	nameID typeID [loadmem]
+ *	BEGIN
+ *		[raw-data]
+ *	END
+ *
+ *****************************************************************************
+ *
+ * Dialog controls:
+ *	CONTROL		text, ID, class, style, x, y, width, height [, exstyle]
+ *
+ *	LTEXT		text, ID, x, y, width, height [, style [, exstyle]]
+ *	CTEXT		text, ID, x, y, width, height [, style [, exstyle]]
+ *	RTEXT		text, ID, x, y, width, height [, style [, exstyle]]
+ *
+ *	ICON		text, ID, x, y, [width, height , style [, exstyle]]
+ *
+ *	EDITTEXT	ID, x, y, width, height [, style [, exstyle]]
+ *
+ *	AUTO3STATE	text, ID, x, y, width, height [, style [, exstyle]]
+ *	AUTOCHECKBOX	text, ID, x, y, width, height [, style [, exstyle]]
+ *	AUTORADIOBUTTON	text, ID, x, y, width, height [, style [, exstyle]]
+ *	STATE3		text, ID, x, y, width, height [, style [, exstyle]]
+ *	CHECKBOX	text, ID, x, y, width, height [, style [, exstyle]]
+ *	PUSHBUTTON	text, ID, x, y, width, height [, style [, exstyle]]
+ *	RADIOBUTTON	text, ID, x, y, width, height [, style [, exstyle]]
+ *	DEFPUSHBUTTON	text, ID, x, y, width, height [, style [, exstyle]]
+ *
+ *	COMBOBOX	text, ID, x, y, width, height [, style [, exstyle]]
+ *	GROUPBOX	text, ID, x, y, width, height [, style [, exstyle]]
+ *	LISTBOX		text, ID, x, y, width, height [, style [, exstyle]]
+ *	SCROLLBAR	text, ID, x, y, width, height [, style [, exstyle]]
+ *
+ * FIXME: This is documented, but I don't know the BS_PUSHBOX style
+ *	PUSHBOX		text, ID, x, y, width, height [, style [, exstyle]]
+\*****************************************************************************/
+
diff --git a/tools/wrc/wrc.h b/tools/wrc/wrc.h
new file mode 100644
index 0000000..13ad29e
--- /dev/null
+++ b/tools/wrc/wrc.h
@@ -0,0 +1,89 @@
+/*
+ * Main definitions and externals
+ *
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ */
+
+#ifndef __WRC_WRC_H
+#define __WRC_WRC_H
+
+#ifndef __WRC_WRCTYPES_H
+#include "wrctypes.h"
+#endif
+
+#define WRC_VERSION	"1.0.0"
+#define WRC_RELEASEDATE	"(28-May-1998)"
+#define WRC_FULLVERSION WRC_VERSION " " WRC_RELEASEDATE
+
+/* Only used in heavy debugging sessions */
+#define HEAPCHECK()
+
+/* Memory/load flags */
+#define WRC_MO_MOVEABLE		0x0010
+#define WRC_MO_PURE		0x0020
+#define WRC_MO_PRELOAD		0x0040
+#define WRC_MO_DISCARDABLE	0x1000
+
+/* Resource type IDs */
+#define WRC_RT_CURSOR		(1)
+#define WRC_RT_BITMAP		(2)
+#define WRC_RT_ICON		(3)
+#define WRC_RT_MENU		(4)
+#define WRC_RT_DIALOG		(5)
+#define WRC_RT_STRING		(6)
+#define WRC_RT_FONTDIR		(7)
+#define WRC_RT_FONT		(8)
+#define WRC_RT_ACCELERATOR	(9)
+#define WRC_RT_RCDATA		(10)
+#define WRC_RT_MESSAGETABLE	(11)
+#define WRC_RT_GROUP_CURSOR	(12)
+#define WRC_RT_GROUP_ICON	(14)
+#define WRC_RT_VERSION		(16)
+#define WRC_RT_DLGINCLUDE	(17)
+#define WRC_RT_PLUGPLAY		(19)
+#define WRC_RT_VXD		(20)
+#define WRC_RT_ANICURSOR	(21)
+#define WRC_RT_ANIICON		(22)
+
+/* Default class type IDs */
+#define CT_BUTTON	0x80
+#define CT_EDIT		0x81
+#define CT_STATIC 	0x82
+#define CT_LISTBOX	0x83
+#define CT_SCROLLBAR	0x84
+#define CT_COMBOBOX	0x85
+
+/* From wrc.c */
+extern int debuglevel;
+#define DEBUGLEVEL_NONE		0x0000
+#define DEBUGLEVEL_CHAT		0x0001
+#define DEBUGLEVEL_DUMP		0x0002
+#define DEBUGLEVEL_TRACE	0x0004
+
+extern int win32;
+extern int constant;
+extern int create_res;
+extern int extensions;
+extern int binary;
+extern int create_header;
+extern int create_dir;
+extern int global;
+extern int indirect;
+extern int indirect_only;
+extern int alignment;
+extern int alignment_pwr;
+extern int create_s;
+extern DWORD codepage;
+extern int pedantic;
+
+extern char *prefix;
+extern char *output_name;
+extern char *input_name;
+extern char *header_name;
+extern char *cmdline;			
+
+extern resource_t *resource_top;
+extern language_t *currentlanguage;
+
+#endif
diff --git a/tools/wrc/wrctypes.h b/tools/wrc/wrctypes.h
new file mode 100644
index 0000000..00075de
--- /dev/null
+++ b/tools/wrc/wrctypes.h
@@ -0,0 +1,467 @@
+/*
+ * General type definitions
+ *
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ */
+
+#ifndef __WRC_WRCTYPES_H
+#define __WRC_WRCTYPES_H
+
+/* First is MS style, second wine style */
+#if !defined(_INC_WINDOWS) && !defined(__WINE_WINDOWS_H)
+#include "windows.h"
+#endif
+
+#ifndef MAKELANGID
+#include "winnls.h"
+#endif
+
+#ifndef VS_FFI_SIGNATURE
+#include "ver.h"
+#endif
+
+
+/* Binary resource structure */
+#define RES_BLOCKSIZE	512
+
+typedef struct res {
+	int	allocsize;	/* Allocated datablock size */
+	int	size;		/* Actual size of data */
+	int	dataidx;	/* Tag behind the resource-header */
+	char	*data;
+} res_t;
+
+/* Resource strings are slightly more complex because they include '\0' */
+enum str_e {str_char, str_unicode};
+
+typedef struct string {
+	int 		size;
+	enum str_e	type;
+	union {
+		char *cstr;
+		short *wstr;
+	} str;
+} string_t;
+
+/* Resources are identified either by name or by number */
+enum name_e {name_str, name_ord};
+
+typedef struct name_id {
+	union {
+		string_t *s_name;
+		int	i_name;
+	} name;
+	enum name_e type;
+} name_id_t;
+
+/* Language definitions */
+typedef struct language {
+	int	id;
+	int	sub;
+} language_t;
+
+typedef DWORD characts_t;
+typedef DWORD version_t;
+
+typedef struct lvc {
+	language_t	*language;
+	version_t	*version;
+	characts_t	*characts;
+} lvc_t;
+
+typedef struct font_id {
+	string_t	*name;
+	int		size;
+	int		weight;
+	int		italic;
+} font_id_t;
+
+/* resource types */
+/* These are in the same order (and ordinal) as the RT_xxx
+ * defines. This is _required_.
+ * I rolled my own numbers for the win32 extension that are
+ * documented, but generate either old RT_xxx numbers, or
+ * don't have an ordinal associated (user type).
+ * I don't know any specs for those noted such, for that matter,
+ * I don't even know whether they can be generated other than by
+ * using a user-type resource.
+ */
+enum res_e {
+	res_0 = 0,
+	res_cur,
+	res_ico,
+	res_bmp,
+	res_men,
+	res_dlg,
+	res_stt,
+	res_fntdir,
+	res_fnt,
+	res_acc,
+	res_rdt,
+	res_msg,
+	res_curg,
+	res_13,		/* Hm, wonder why its not used... */
+	res_icog,
+	res_15,
+	res_ver,
+	res_dlginc,	/* Not implemented, no layout available */
+	res_18,
+	res_pnp,	/* Not implemented, no layout available */
+	res_vxd,	/* Not implemented, no layout available */
+	res_anicur,	/* Not implemented, no layout available */
+	res_aniico,	/* Not implemented, no layout available */
+
+	res_menex = 256 + 4,
+	res_dlgex,
+	res_usr,
+};
+
+/* Raw bytes in a row... */
+typedef struct raw_data {
+	int	size;
+	char	*data;
+} raw_data_t;
+
+/* Dialog structures */
+typedef struct control {
+	struct control	*next;		/* List of controls */
+	struct control	*prev;
+	name_id_t	*ctlclass;	/* ControlClass */
+	string_t	*title;		/* Title of control */
+	int		id;
+	int		x;		/* Position */
+	int		y;
+	int		width;		/* Size */
+	int		height;
+	DWORD		style;		/* Style */
+	DWORD		exstyle;
+	DWORD		helpid;		/* EX: */
+	int		gotstyle;	/* Used to determine whether the default */
+	int		gotexstyle;	/* styles must be set */
+	int		gothelpid;
+	raw_data_t	*extra;		/* EX: number of extra bytes in resource */
+} control_t;
+
+typedef struct dialog {
+	DWORD		memopt;
+	int		x;		/* Position */
+	int		y;
+	int		width;		/* Size */
+	int		height;
+	DWORD		style;		/* Style */
+	DWORD		exstyle;
+	int		gotstyle;	/* Used to determine whether the default */
+	int		gotexstyle;	/* styles must be set */
+	name_id_t	*menu;
+	name_id_t	*dlgclass;
+	string_t	*title;
+	font_id_t	*font;
+	lvc_t		lvc;
+	control_t	*controls;
+} dialog_t;
+
+/* DialogEx structures */
+typedef struct dialogex {
+	DWORD		memopt;
+	int		x;		/* Position */
+	int		y;
+	int		width;		/* Size */
+	int		height;
+	DWORD		style;		/* Style */
+	DWORD		exstyle;
+	DWORD		helpid;		/* EX: */
+	int		gotstyle;	/* Used to determine whether the default */
+	int		gotexstyle;	/* styles must be set */
+	int		gothelpid;
+	name_id_t	*menu;
+	name_id_t	*dlgclass;
+	string_t	*title;
+	font_id_t	*font;
+	lvc_t		lvc;
+	control_t	*controls;
+} dialogex_t;
+
+/* Menu structures */
+typedef struct menu_item {
+	struct menu_item *next;
+	struct menu_item *prev;
+	struct menu_item *popup;
+	int		id;
+	DWORD		state;
+	string_t	*name;
+} menu_item_t;
+
+typedef struct menu {
+	DWORD		memopt;
+	lvc_t		lvc;
+	menu_item_t	*items;
+} menu_t;
+
+/* MenuEx structures */
+typedef struct menuex_item {
+	struct menuex_item *next;
+	struct menuex_item *prev;
+	struct menuex_item *popup;
+	int		id;
+	DWORD		type;
+	DWORD		state;
+	int		helpid;
+	string_t	*name;
+	int		gotid;
+	int		gottype;
+	int		gotstate;
+	int		gothelpid;
+} menuex_item_t;
+
+typedef struct menuex {
+	DWORD		memopt;
+	lvc_t		lvc;
+	menuex_item_t	*items;
+} menuex_t;
+
+typedef struct itemex_opt
+{
+	int	id;
+	DWORD	type;
+	DWORD	state;
+	int	helpid;
+	int	gotid;
+	int	gottype;
+	int	gotstate;
+	int	gothelpid;
+} itemex_opt_t;
+
+/* RC structures for types read from file or supplied binary */
+typedef struct font {
+	DWORD		memopt;
+	raw_data_t	*data;
+} font_t;
+
+typedef struct icon_dir_entry {
+    BYTE  width;	/* From the SKD doc. */
+    BYTE  height;
+    BYTE  nclr;
+    BYTE  reserved;
+    WORD  planes;
+    WORD  bits;
+    DWORD ressize;
+    DWORD offset;
+} icon_dir_entry_t;
+
+typedef struct icon {
+	struct icon	*next;
+	struct icon	*prev;
+	int		id;	/* Unique icon id within resource file */
+	int		width;	/* Field from the IconDirEntry */
+	int		height;
+	int		nclr;
+	int		planes;
+	int		bits;
+	raw_data_t	*data;
+} icon_t;
+
+typedef struct icon_group {
+	DWORD		memopt;
+	icon_t		*iconlist;
+	int		nicon;
+} icon_group_t;
+
+typedef struct cursor_dir_entry {
+    BYTE  width;	/* From the SKD doc. */
+    BYTE  height;
+    BYTE  nclr;
+    BYTE  reserved;
+    WORD  xhot;
+    WORD  yhot;
+    DWORD ressize;
+    DWORD offset;
+} cursor_dir_entry_t;
+
+typedef struct cursor {
+	struct cursor	*next;
+	struct cursor	*prev;
+	int		id;	/* Unique icon id within resource file */
+	int		width;	/* Field from the CursorDirEntry */
+	int		height;
+	int		nclr;
+	int		planes;
+	int		bits;
+	int		xhot;
+	int		yhot;
+	raw_data_t	*data;
+} cursor_t;
+
+typedef struct cursor_group {
+	DWORD		memopt;
+	cursor_t	*cursorlist;
+	int		ncursor;
+} cursor_group_t;
+
+typedef struct bitmap {
+	DWORD		memopt;
+	raw_data_t	*data;
+} bitmap_t;
+
+typedef struct rcdata {
+	DWORD		memopt;
+	lvc_t		lvc;
+	raw_data_t	*data;
+} rcdata_t;
+
+typedef struct user {
+	DWORD		memopt;
+	name_id_t	*type;
+	raw_data_t	*data;
+} user_t;
+
+typedef struct messagetable {
+	raw_data_t	*data;
+} messagetable_t;
+
+/* StringTable structures */
+typedef struct stt_entry {
+	string_t		*str;
+	int			id;
+	DWORD			memopt;
+	characts_t		*characts;
+	version_t		*version;
+} stt_entry_t;
+
+typedef struct stringtable {
+	struct stringtable	*next;
+	struct stringtable	*prev;
+	DWORD			memopt;
+	lvc_t			lvc;
+	int			idbase;
+	int			nentries;
+	stt_entry_t		*entries;
+} stringtable_t;
+
+/* VersionInfo structures */
+enum ver_val_e {val_str, val_words, val_block};
+
+struct ver_block;	/* Forward ref */
+
+typedef struct ver_words {
+	WORD	*words;
+	int	nwords;
+} ver_words_t;
+
+typedef struct ver_value {
+	struct ver_value	*next;
+	struct ver_value	*prev;
+	string_t		*key;
+	union {
+		string_t		*str;
+		ver_words_t		*words;
+		struct ver_block	*block;
+	} value;
+	enum ver_val_e		type;
+} ver_value_t;
+
+typedef struct ver_block {
+	struct ver_block	*next;
+	struct ver_block	*prev;
+	string_t		*name;
+	ver_value_t		*values;
+} ver_block_t;
+
+typedef struct versioninfo {
+	int	filever_maj1;
+	int	filever_maj2;
+	int	filever_min1;
+	int	filever_min2;
+	int	prodver_maj1;
+	int	prodver_maj2;
+	int	prodver_min1;
+	int	prodver_min2;
+	int	fileos;
+	int	fileflags;
+	int	fileflagsmask;
+	int	filetype;
+	int	filesubtype;
+	struct {
+		int fv:1;
+		int pv:1;
+		int fo:1;
+		int ff:1;
+		int ffm:1;
+		int ft:1;
+		int fst:1;
+	} gotit;
+	ver_block_t	*blocks;
+} versioninfo_t;
+
+/* Accelerator structures */
+#define WRC_AF_VIRTKEY	0x0001
+#define WRC_AF_NOINVERT	0x0002
+#define WRC_AF_SHIFT	0x0004
+#define WRC_AF_CONTROL	0x0008
+#define WRC_AF_ALT	0x0010
+#define WRC_AF_ASCII	0x4000
+
+typedef struct event {
+	struct event	*next;
+	struct event	*prev;
+	int		flags;
+	int		key;
+	int		id;
+} event_t;
+
+typedef struct accelerator {
+	DWORD		memopt;
+	lvc_t		lvc;
+	event_t		*events;
+} accelerator_t;
+
+/* A top-level resource node */
+typedef struct resource {
+	struct resource	*next;
+	struct resource *prev;
+	enum res_e	type;
+	name_id_t	*name;	/* resource's name */
+	language_t	*lan;	/* Only used as a sorting key and c-name creation*/
+	union {
+		accelerator_t	*acc;
+		bitmap_t	*bmp;
+		cursor_t	*cur;
+		cursor_group_t	*curg;
+		dialog_t	*dlg;
+		dialogex_t	*dlgex;
+		font_t		*fnt;
+		icon_t		*ico;
+		icon_group_t	*icog;
+		menu_t		*men;
+		menuex_t	*menex;
+		messagetable_t	*msg;
+		rcdata_t	*rdt;
+		stringtable_t	*stt;
+		user_t		*usr;
+		versioninfo_t	*ver;
+		void		*overlay; /* To catch all types at once... */
+	} res;
+	res_t		*binres;	/* To binary converted resource */
+	char		*c_name;	/* BaseName in output */
+	DWORD		memopt;
+} resource_t;
+
+/* Resource count */
+typedef struct res32_count {
+	int			count;
+	resource_t		**rsc;
+} res32_count_t;
+
+typedef struct res_count {
+	name_id_t		type;
+	int			count;		/* win16 mode */
+	resource_t		**rscarray;
+	int			count32;
+	res32_count_t		*rsc32array;	/* win32 mode */
+	int			n_id_entries;
+	int			n_name_entries;
+} res_count_t;
+
+#endif
+
+
diff --git a/tools/wrc/writeres.c b/tools/wrc/writeres.c
new file mode 100644
index 0000000..18084f0
--- /dev/null
+++ b/tools/wrc/writeres.c
@@ -0,0 +1,1134 @@
+/*
+ * Write .res, .s and .h file(s) from a resource-tree
+ *
+ * Copyright 1998 Bertho A. Stultiens
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+#include <config.h>
+#include "wrc.h"
+#include "writeres.h"
+#include "genres.h"
+#include "newstruc.h"
+#include "utils.h"
+
+char s_file_head_str[] =
+	"#\n"
+	"# This file is generated with wrc version " WRC_FULLVERSION ". Do not edit!\n"
+	"# Source : %s\n"
+	"# Cmdline: %s\n"
+	"# Date   : %s"
+	"#\n\n"
+	"\t.data\n\n"
+	;
+
+char s_file_tail_str[] =
+	"# <eof>\n\n"
+	;
+
+char h_file_head_str[] =
+	"/*\n"
+	" * This file is generated with wrc version " WRC_FULLVERSION ". Do not edit!\n"
+	" * Source : %s\n"
+	" * Cmdline: %s\n"
+	" * Date   : %s"
+	" */\n\n"
+	"#ifndef __%08x_H\n"	/* This becomes the data of compile */
+	"#define __%08x_H\n\n"
+	"#ifndef __WRC_RSC_H\n"
+	"#include <wrc_rsc.h>\n"
+	"#endif\n\n"
+	;
+
+char h_file_tail_str[] =
+	"#endif\n"
+	"/* <eof> */\n\n"
+	;
+
+char _NEResTab[] = "_NEResTab";
+char _PEResTab[] = "_PEResTab";
+char _ResTable[] = "_ResTable";
+
+res_count_t *rcarray = NULL;
+int rccount = 0;
+int n_id_entries = 0;
+int n_name_entries = 0;
+
+time_t now;
+
+/*
+ *****************************************************************************
+ * Function	: write_resfile
+ * Syntax	: void write_resfile(char *outname, resource_t *top)
+ * Input	:
+ *	outname	- Filename to write to
+ *	top	- The resource-tree to convert
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void write_resfile(char *outname, resource_t *top)
+{
+	FILE *fo;
+	int ret;
+	char zeros[3] = {0, 0, 0};
+
+	fo = fopen(outname, "wb");
+	if(!fo)
+	{
+		error("Could not open %s\n", outname);
+	}
+
+	if(win32)
+	{
+		/* Put an empty resource first to signal win32 format */
+		res_t *res = new_res();
+		put_dword(res, 0);		/* ResSize */
+		put_dword(res, 0x00000020);	/* HeaderSize */
+		put_word(res, 0xffff);		/* ResType */
+		put_word(res, 0);
+		put_word(res, 0xffff);		/* ResName */
+		put_word(res, 0);
+		put_dword(res, 0);		/* DataVersion */
+		put_word(res, 0);		/* Memory options */
+		put_word(res, 0);		/* Language */
+		put_dword(res, 0);		/* Version */
+		put_dword(res, 0);		/* Charateristics */
+		ret = fwrite(res->data, 1, res->size, fo);
+		if(ret != res->size)
+		{
+			fclose(fo);
+			error("Error writing %s", outname);
+		}
+		free(res);
+	}
+
+	for(; top; top = top->next)
+	{
+		if(!top->binres)
+			continue;
+
+		ret = fwrite(top->binres->data, 1, top->binres->size, fo);
+		if(ret != top->binres->size)
+		{
+			fclose(fo);
+			error("Error writing %s", outname);
+		}
+		if(win32 && (top->binres->size & 0x03))
+		{
+			/* Write padding */
+			ret = fwrite(zeros, 1, 4 - (top->binres->size & 0x03), fo);
+			if(ret != 4 - (top->binres->size & 0x03))
+			{
+				fclose(fo);
+				error("Error writing %s", outname);
+			}
+		}
+	}
+	fclose(fo);
+}
+
+/*
+ *****************************************************************************
+ * Function	: write_s_res
+ * Syntax	: void write_s_res(FILE *fp, res_t *res)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+#define BYTESPERLINE	8
+void write_s_res(FILE *fp, res_t *res)
+{
+	int idx = res->dataidx;
+	int end = res->size;
+	int rest = (end - idx) % BYTESPERLINE;
+	int lines = (end - idx) / BYTESPERLINE;
+	int i, j;
+
+	for(i = 0 ; i < lines; i++)
+	{
+		fprintf(fp, "\t.byte\t");
+		for(j = 0; j < BYTESPERLINE; j++, idx++)
+		{
+			fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
+					j == BYTESPERLINE-1 ? "" : ", ");
+		}
+		fprintf(fp, "\n");
+	}
+	if(rest)
+	{
+		fprintf(fp, "\t.byte\t");
+		for(j = 0; j < rest; j++, idx++)
+		{
+			fprintf(fp, "0x%02x%s", res->data[idx] & 0xff,
+					j == rest-1 ? "" : ", ");
+		}
+		fprintf(fp, "\n");
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: write_name_str
+ * Syntax	: void write_name_str(FILE *fp, name_id_t *nid)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	: One level self recursive for string type conversion
+ *****************************************************************************
+*/
+void write_name_str(FILE *fp, name_id_t *nid)
+{
+	res_t res;
+	assert(nid->type == name_str);
+
+	if(!win32 && nid->name.s_name->type == str_char)
+	{
+		res.size = strlen(nid->name.s_name->str.cstr) + 1;
+		if(res.size > 254)
+			error("Can't write strings larger than 254 bytes");
+		if(res.size == 0)
+			internal_error(__FILE__, __LINE__, "Attempt to write empty string");
+		res.dataidx = 0;
+		res.data = (char *)xmalloc(res.size);
+		res.data[0] = (char)res.size;
+		strcpy(res.data+1, nid->name.s_name->str.cstr);
+		write_s_res(fp, &res);
+		free(res.data);
+	}
+	else if(!win32 && nid->name.s_name->type == str_unicode)
+	{
+		name_id_t lnid;
+		string_t str;
+
+		lnid.type = name_str;
+		lnid.name.s_name = &str;
+		str.type = str_char;
+		str.str.cstr = dupwstr2cstr(nid->name.s_name->str.wstr);
+		write_name_str(fp, &lnid);
+		free(str.str.cstr);
+	}
+	else if(win32 && nid->name.s_name->type == str_char)
+	{
+		name_id_t lnid;
+		string_t str;
+
+		lnid.type = name_str;
+		lnid.name.s_name = &str;
+		str.type = str_unicode;
+		str.str.wstr = dupcstr2wstr(nid->name.s_name->str.cstr);
+		write_name_str(fp, &lnid);
+		free(str.str.wstr);
+	}
+	else  if(win32 && nid->name.s_name->type == str_unicode)
+	{
+		res.size = wstrlen(nid->name.s_name->str.wstr) + 1;
+		if(res.size > 65534)
+			error("Can't write strings larger than 65534 bytes");
+		if(res.size == 0)
+			internal_error(__FILE__, __LINE__, "Attempt to write empty string");
+		res.dataidx = 0;
+		res.data = (char *)xmalloc(res.size * 2);
+		((short *)res.data)[0] = (char)res.size;
+		wstrcpy((short *)(res.data+2), nid->name.s_name->str.wstr);
+		res.size *= 2; /* Function writes bytes, not shorts... */
+		write_s_res(fp, &res);
+		free(res.data);
+	}
+	else
+	{
+		internal_error(__FILE__, __LINE__, "Hmm, requested to write a string of unknown type %d",
+				nid->name.s_name->type);
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: compare_name_id
+ * Syntax	: int compare_name_id(name_id_t *n1, name_id_t *n2)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+int compare_name_id(name_id_t *n1, name_id_t *n2)
+{
+	if(n1->type == name_ord && n2->type == name_ord)
+	{
+		return n1->name.i_name - n2->name.i_name;
+	}
+	else if(n1->type == name_str && n2->type == name_str)
+	{
+		if(n1->name.s_name->type == str_char
+		&& n2->name.s_name->type == str_char)
+		{
+			return stricmp(n1->name.s_name->str.cstr, n2->name.s_name->str.cstr);
+		}
+		else if(n1->name.s_name->type == str_unicode
+		&& n2->name.s_name->type == str_unicode)
+		{
+			return wstricmp(n1->name.s_name->str.wstr, n2->name.s_name->str.wstr);
+		}
+		else
+		{
+			internal_error(__FILE__, __LINE__, "Can't yet compare strings of mixed type");
+		}
+	}
+	else if(n1->type == name_ord && n2->type == name_str)
+		return -1;
+	else if(n1->type == name_str && n2->type == name_ord)
+		return 1;
+	else
+		internal_error(__FILE__, __LINE__, "Comparing name-ids with unknown types (%d, %d)",
+				n1->type, n2->type);
+
+	return 0; /* Keep the compiler happy */
+}
+
+/*
+ *****************************************************************************
+ * Function	: find_counter
+ * Syntax	: res_count_t *find_counter(name_id_t *type)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+res_count_t *find_counter(name_id_t *type)
+{
+	int i;
+	for(i = 0; i < rccount; i++)
+	{
+		if(!compare_name_id(type, &(rcarray[i].type)))
+			return &rcarray[i];
+	}
+	return NULL;
+}
+
+/*
+ *****************************************************************************
+ * Function	: count_resources
+ * Syntax	: res_count_t *count_resources(resource_t *top)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	: The whole lot is converted into arrays because they are
+ *		  easy sortable. Makes the lot almost unreadable, but it
+ *		  works (I hope). Basically you have to keep in mind that
+ *		  the lot is a three-dimensional structure for win32 and a
+ *		  two-dimensional structure for win16.
+ *****************************************************************************
+*/
+#define RCT(v)	(*((resource_t **)(v)))
+/* qsort sorting function */
+int sort_name_id(const void *e1, const void *e2)
+{
+	return compare_name_id(RCT(e1)->name, RCT(e2)->name);
+}
+
+int sort_language(const void *e1, const void *e2)
+{
+	assert((RCT(e1)->lan) != NULL);
+	assert((RCT(e2)->lan) != NULL);
+
+	return MAKELANGID(RCT(e1)->lan->id, RCT(e1)->lan->sub)
+	     - MAKELANGID(RCT(e2)->lan->id, RCT(e2)->lan->sub);
+}
+#undef RCT
+#define RCT(v)	((res_count_t *)(v))
+int sort_type(const void *e1, const void *e2)
+{
+	return compare_name_id(&(RCT(e1)->type), &(RCT(e2)->type));
+}
+#undef RCT
+
+void count_resources(resource_t *top)
+{
+	resource_t *rsc;
+	res_count_t *rcp;
+	name_id_t nid;
+	int i, j;
+
+	for(rsc = top; rsc; rsc = rsc->next)
+	{
+		if(!rsc->binres)
+			continue;
+		switch(rsc->type)
+		{
+		case res_dlgex:
+			nid.name.i_name = WRC_RT_DIALOG;
+			nid.type = name_ord;
+			break;
+		case res_menex:
+			nid.name.i_name = WRC_RT_MENU;
+			nid.type = name_ord;
+			break;
+		case res_usr:
+			nid = *(rsc->res.usr->type);
+			break;
+		default:
+			nid.name.i_name = rsc->type;
+			nid.type = name_ord;
+		}
+
+		if((rcp = find_counter(&nid)) == NULL)
+		{
+			/* Count the number of uniq ids and names */
+
+			if(nid.type == name_ord)
+				n_id_entries++;
+			else
+				n_name_entries++;
+
+			if(!rcarray)
+			{
+				rcarray = (res_count_t *)xmalloc(sizeof(res_count_t));
+				rccount = 1;
+				rcarray[0].count = 1;
+				rcarray[0].type = nid;
+				rcarray[0].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
+				rcarray[0].rscarray[0] = rsc;
+			}
+			else
+			{
+				rccount++;
+				rcarray = (res_count_t *)xrealloc(rcarray, rccount * sizeof(res_count_t));
+				rcarray[rccount-1].count = 1;
+				rcarray[rccount-1].type = nid;
+				rcarray[rccount-1].rscarray = (resource_t **)xmalloc(sizeof(resource_t *));
+				rcarray[rccount-1].rscarray[0] = rsc;
+			}
+		}
+		else
+		{
+			rcp->count++;
+			rcp->rscarray = (resource_t **)xrealloc(rcp->rscarray, rcp->count * sizeof(resource_t *));
+			rcp->rscarray[rcp->count-1] = rsc;
+		}
+	}
+
+	if(!win32)
+	{
+		/* We're done, win16 requires no special sorting */
+		return;
+	}
+
+	/* We now have a unsorted list of types with an array of res_count_t
+	 * in rcarray[0..rccount-1]. And we have names of one type in the
+	 * rcarray[x].rsc[0..rcarray[x].count-1] arrays.
+	 * The list needs to be sorted for win32's top level tree structure.
+	 */
+
+	/* Sort the types */
+	if(rccount > 1)
+		qsort(rcarray, rccount, sizeof(rcarray[0]), sort_type);
+
+	/* Now sort the name-id arrays */
+	for(i = 0; i < rccount; i++)
+	{
+		if(rcarray[i].count > 1)
+			qsort(rcarray[i].rscarray, rcarray[i].count, sizeof(rcarray[0].rscarray[0]), sort_name_id);
+	}
+
+	/* Now split the name-id arrays into name/language
+	 * subs. Don't look at the awfull expressions...
+	 * We do this by taking the array elements out of rscarray and putting
+	 * together a new array in rsc32array.
+	 */
+	for(i = 0; i < rccount; i++)
+	{
+		res_count_t *rcap;
+
+		assert(rcarray[i].count >= 1);
+
+		/* rcap points to the current type we are dealing with */
+		rcap = &(rcarray[i]);
+
+		/* Insert the first name-id */
+		rcap->rsc32array = (res32_count_t *)xmalloc(sizeof(res32_count_t));
+		rcap->count32 = 1;
+		rcap->rsc32array[0].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
+		rcap->rsc32array[0].count = 1;
+		rcap->rsc32array[0].rsc[0] = rcap->rscarray[0];
+		if(rcap->rscarray[0]->name->type == name_ord)
+		{
+			rcap->n_id_entries = 1;
+			rcap->n_name_entries = 0;
+		}
+		else
+		{
+			rcap->n_id_entries = 0;
+			rcap->n_name_entries = 1;
+		}
+
+		/* Now loop over the resting resources of the current type
+		 * to find duplicate names (which should have different
+		 * languages).
+		 */
+		for(j = 1; j < rcap->count; j++)
+		{
+			res32_count_t *r32cp;
+
+			/* r32cp points to the current res32_count structure
+			 * that holds the resource name we are processing.
+			 */
+			r32cp = &(rcap->rsc32array[rcap->count32-1]);
+
+			if(!compare_name_id(r32cp->rsc[0]->name, rcarray[i].rscarray[j]->name))
+			{
+				/* Names are the same, add to list */
+				r32cp->count++;
+				r32cp->rsc = (resource_t **)xrealloc(r32cp->rsc, r32cp->count * sizeof(resource_t *));
+				r32cp->rsc[r32cp->count-1] = rcap->rscarray[j];
+
+				if(rcap->rscarray[j]->name->type == name_ord)
+				{
+					rcap->n_id_entries = 1;
+					rcap->n_name_entries = 0;
+				}
+				else
+				{
+					rcap->n_id_entries = 0;
+					rcap->n_name_entries = 1;
+				}
+			}
+			else
+			{
+				/* New name-id, sort the old one by
+				 * language and create new list
+				 */
+				if(r32cp->count > 1)
+					qsort(r32cp->rsc, r32cp->count, sizeof(r32cp->rsc[0]), sort_language);
+				rcap->count32++;
+				rcap->rsc32array = (res32_count_t*)xrealloc(rcap->rsc32array, rcap->count32 * sizeof(res32_count_t));
+				rcap->rsc32array[rcap->count32-1].rsc = (resource_t **)xmalloc(sizeof(resource_t *));
+				rcap->rsc32array[rcap->count32-1].count = 1;
+				rcap->rsc32array[rcap->count32-1].rsc[0] = rcap->rscarray[j];
+
+				if(rcap->rscarray[j]->name->type == name_ord)
+					rcap->n_id_entries++;
+				else
+					rcap->n_name_entries++;
+			}
+		}
+		/* Also sort the languages of the last name group */
+		if(rcap->rsc32array[rcap->count32-1].count > 1)
+			qsort(rcap->rsc32array[rcap->count32-1].rsc,
+			      rcap->rsc32array[rcap->count32-1].count,
+			      sizeof(rcap->rsc32array[rcap->count32-1].rsc[0]),
+			      sort_language);
+	}
+}
+
+/*
+ *****************************************************************************
+ * Function	: write_pe_segment
+ * Syntax	: void write_pe_segment(FILE *fp, resource_t *top)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void write_pe_segment(FILE *fp, resource_t *top)
+{
+	int i;
+
+	fprintf(fp, "\t.align\t4\n");
+	fprintf(fp, "%s%s:\n", prefix, _PEResTab);
+	fprintf(fp, "\t.globl\t%s%s\n", prefix, _PEResTab);
+	/* Flags */
+	fprintf(fp, "\t.long\t0\n");
+	/* Time/Date stamp */
+	fprintf(fp, "\t.long\t0x%08lx\n", now);
+	/* Version */
+	fprintf(fp, "\t.long\t0\n");	/* FIXME: must version be filled out? */
+	/* # of id entries, # of name entries */
+	fprintf(fp, "\t.short\t%d, %d\n", n_name_entries, n_id_entries);
+
+	/* Write the type level of the tree */
+	for(i = 0; i < rccount; i++)
+	{
+		res_count_t *rcp;
+		char *label;
+
+		rcp = &rcarray[i];
+
+		/* TypeId */
+		if(rcp->type.type == name_ord)
+			fprintf(fp, "\t.long\t%d\n", rcp->type.name.i_name);
+		else
+		{
+			char *name = prep_nid_for_label(&(rcp->type));
+			fprintf(fp, "\t.long\t(%s_%s_typename - %s%s) | 0x80000000\n",
+				prefix,
+				name,
+				prefix,
+				_PEResTab);
+		}
+		/* Offset */
+		label = prep_nid_for_label(&(rcp->type));
+		fprintf(fp, "\t.long\t(.L%s - %s%s) | 0x80000000\n",
+			label,
+			prefix,
+			_PEResTab);
+	}
+
+	/* Write the name level of the tree */
+
+	for(i = 0; i < rccount; i++)
+	{
+		res_count_t *rcp;
+		char *typelabel;
+		char *namelabel;
+		int j;
+
+		rcp = &rcarray[i];
+
+		typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
+		fprintf(fp, ".L%s:\n", typelabel);
+
+		fprintf(fp, "\t.long\t0\n");		/* Flags */
+		fprintf(fp, "\t.long\t0x%08lx\n", now);	/* TimeDate */
+		fprintf(fp, "\t.long\t0\n");	/* FIXME: must version be filled out? */
+		fprintf(fp, "\t.short\t%d, %d\n", rcp->n_name_entries, rcp->n_id_entries);
+		for(j = 0; j < rcp->count32; j++)
+		{
+			resource_t *rsc = rcp->rsc32array[j].rsc[0];
+			/* NameId */
+			if(rsc->name->type == name_ord)
+				fprintf(fp, "\t.long\t%d\n", rsc->name->name.i_name);
+			else
+			{
+				fprintf(fp, "\t.long\t(%s%s_name - %s%s) | 0x80000000\n",
+					prefix,
+					rsc->c_name,
+					prefix,
+					_PEResTab);
+			}
+			/* Maybe FIXME: Unescape the tree (ommit 0x80000000) and
+			 * put the offset to the resource data entry.
+			 * ?? Is unescaping worth while ??
+			 */
+			/* Offset */
+			namelabel = prep_nid_for_label(rsc->name);
+			fprintf(fp, "\t.long\t(.L%s_%s - %s%s) | 0x80000000\n",
+				typelabel,
+				namelabel,
+				prefix,
+				_PEResTab);
+		}
+		free(typelabel);
+	}
+
+	/* Write the language level of the tree */
+
+	for(i = 0; i < rccount; i++)
+	{
+		res_count_t *rcp;
+		char *namelabel;
+		char *typelabel;
+		int j;
+
+		rcp = &rcarray[i];
+		typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
+
+		for(j = 0; j < rcp->count32; j++)
+		{
+			res32_count_t *r32cp = &(rcp->rsc32array[j]);
+			int k;
+
+			namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
+			fprintf(fp, ".L%s_%s:\n", typelabel, namelabel);
+
+			fprintf(fp, "\t.long\t0\n");		/* Flags */
+			fprintf(fp, "\t.long\t0x%08lx\n", now);	/* TimeDate */
+			fprintf(fp, "\t.long\t0\n");	/* FIXME: must version be filled out? */
+			fprintf(fp, "\t.short\t0, %d\n", r32cp->count);
+
+			for(k = 0; k < r32cp->count; k++)
+			{
+				resource_t *rsc = r32cp->rsc[k];
+				assert(rsc->lan != NULL);
+				/* LanguageId */
+				fprintf(fp, "\t.long\t0x%08x\n", rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
+				/* Offset */
+				fprintf(fp, "\t.long\t.L%s_%s_%d - %s%s\n",
+					typelabel,
+					namelabel,
+					rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0,
+					prefix,
+					_PEResTab);
+			}
+			free(namelabel);
+		}
+		free(typelabel);
+	}
+
+	/* Write the resource table itself */
+
+	for(i = 0; i < rccount; i++)
+	{
+		res_count_t *rcp;
+		char *namelabel;
+		char *typelabel;
+		int j;
+
+		rcp = &rcarray[i];
+		typelabel = xstrdup(prep_nid_for_label(&(rcp->type)));
+
+		for(j = 0; j < rcp->count32; j++)
+		{
+			res32_count_t *r32cp = &(rcp->rsc32array[j]);
+			int k;
+
+			namelabel = xstrdup(prep_nid_for_label(r32cp->rsc[0]->name));
+
+			for(k = 0; k < r32cp->count; k++)
+			{
+				resource_t *rsc = r32cp->rsc[k];
+
+				assert(rsc->lan != NULL);
+
+				fprintf(fp, ".L%s_%s_%d:\n",
+					typelabel,
+					namelabel,
+					rsc->lan ? MAKELANGID(rsc->lan->id, rsc->lan->sub) : 0);
+
+				/* Data RVA */
+				fprintf(fp, "\t.long\t%s%s_data - %s%s\n",
+					prefix,
+					rsc->c_name,
+					prefix,
+					_PEResTab);
+				/* Size */
+				fprintf(fp, "\t.long\t%d\n",
+					rsc->binres->size - rsc->binres->dataidx);
+				/* CodePage */
+				fprintf(fp, "\t.long\t%ld\n", codepage);
+				/* Reserved */
+				fprintf(fp, "\t.long\t0\n");
+			}
+			free(namelabel);
+		}
+		free(typelabel);
+	}
+
+}
+
+/*
+ *****************************************************************************
+ * Function	: write_ne_segment
+ * Syntax	: void write_ne_segment(FILE *fp, resource_t *top)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void write_ne_segment(FILE *fp, resource_t *top)
+{
+	int i, j;
+
+	fprintf(fp, "\t.align\t4\n");
+	fprintf(fp, "%s%s:\n", prefix, _NEResTab);
+	fprintf(fp, "\t.globl\t%s%s\n", prefix, _NEResTab);
+
+	/* AlignmentShift */
+	fprintf(fp, "\t.short\t%d\n", alignment_pwr);
+
+	/* TypeInfo */
+	for(i = 0; i < rccount; i++)
+	{
+		res_count_t *rcp = &rcarray[i];
+
+		/* TypeId */
+		if(rcp->type.type == name_ord)
+			fprintf(fp, "\t.short\t0x%04x\n", rcp->type.name.i_name | 0x8000);
+		else
+			fprintf(fp, "\t.short\t%s_%s_typename - %s%s\n",
+				prefix,
+				rcp->type.name.s_name->str.cstr,
+				prefix,
+				_NEResTab);
+		/* ResourceCount */
+		fprintf(fp, "\t.short\t%d\n", rcp->count);
+		/* Reserved */
+		fprintf(fp, "\t.long\t0\n");
+		/* NameInfo */
+		for(j = 0; j < rcp->count; j++)
+		{
+			/* FIXME: dividing by `alignment` doesn't seem to
+			 * work with as (GAS). Shifting results in the
+			 * correct behaviour. Maybe an as bug or just my
+			 * lack of knowing as expression-syntax.
+			 */
+			/* Offset */
+/*
+ * VERY IMPORTANT:
+ * The offset is relative to the beginning of the NE resource segment
+ * and _NOT_ to the file-beginning. This is because we do not have a
+ * file based resource, but a simulated NE segment. The offset _is_
+ * scaled by the AlignShift field.
+ * All other things are as the MS doc describes (alignment etc.)
+ */
+			fprintf(fp, "\t.short\t(%s%s_data - %s%s) >> %d\n",
+				prefix,
+				rcp->rscarray[j]->c_name,
+				prefix,
+				_NEResTab,
+				alignment_pwr);
+			/* Length */
+			fprintf(fp, "\t.short\t%d\n",
+				rcp->rscarray[j]->binres->size - rcp->rscarray[j]->binres->dataidx);
+			/* Flags */
+			fprintf(fp, "\t.short\t0x%04x\n", (WORD)rcp->rscarray[j]->memopt);
+			/* Id */
+			if(rcp->rscarray[j]->name->type == name_ord)
+				fprintf(fp, "\t.short\t0x%04x\n", rcp->rscarray[j]->name->name.i_name | 0x8000);
+			else
+				fprintf(fp, "\t.short\t%s%s_name - %s%s\n",
+				prefix,
+				rcp->rscarray[j]->c_name,
+				prefix,
+				_NEResTab);
+			/* Handle and Usage */
+			fprintf(fp, "\t.short\t0, 0\n");
+		}
+	}
+	/* EndTypes */
+	fprintf(fp, "\t.short\t0\n");
+}
+
+/*
+ *****************************************************************************
+ * Function	: write_rsc_names
+ * Syntax	: void write_rsc_names(FILE *fp, resource_t *top)
+ * Input	:
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void write_rsc_names(FILE *fp, resource_t *top)
+{
+	int i, j;
+	
+	if(win32)
+	{
+		/* Write the names */
+
+		for(i = 0; i < rccount; i++)
+		{
+			res_count_t *rcp;
+
+			rcp = &rcarray[i];
+
+			if(rcp->type.type == name_str)
+			{
+				char *name = prep_nid_for_label(&(rcp->type));
+				fprintf(fp, "%s_%s_typename:\n",
+					prefix,
+					name);
+				write_name_str(fp, &(rcp->type));
+			}
+
+			for(j = 0; j < rcp->count32; j++)
+			{
+				resource_t *rsc = rcp->rsc32array[j].rsc[0];
+
+				if(rsc->name->type == name_str)
+				{
+					fprintf(fp, "%s%s_name:\n",
+						prefix,
+						rsc->c_name);
+					write_name_str(fp, rsc->name);
+				}
+			}
+		}
+	}
+	else
+	{
+		/* ResourceNames */
+		for(i = 0; i < rccount; i++)
+		{
+			res_count_t *rcp = &rcarray[i];
+
+			for(j = 0; j < rcp->count; j++)
+			{
+				if(rcp->type.type == name_str)
+				{
+					fprintf(fp, "%s_%s_typename:\n",
+						prefix,
+						rcp->type.name.s_name->str.cstr);
+					write_name_str(fp, &(rcp->type));
+				}
+				if(rcp->rscarray[j]->name->type == name_str)
+				{
+					fprintf(fp, "%s%s_name:\n",
+						prefix,
+						rcp->rscarray[j]->c_name);
+					write_name_str(fp, rcp->rscarray[j]->name);
+				}
+			}
+		}
+		/* EndNames */
+		
+		/* This is to end the NE resource table */
+		if(create_dir)
+			fprintf(fp, "\t.byte\t0\n");
+	}
+
+	fprintf(fp, "\n");
+}
+
+/*
+ *****************************************************************************
+ * Function	: write_s_file
+ * Syntax	: void write_s_file(char *outname, resource_t *top)
+ * Input	:
+ *	outname	- Filename to write to
+ *	top	- The resource-tree to convert
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void write_s_file(char *outname, resource_t *top)
+{
+	FILE *fo;
+	resource_t *rsc;
+
+	fo = fopen(outname, "wt");
+	if(!fo)
+	{
+		error("Could not open %s\n", outname);
+	}
+
+	now = time(NULL);
+	fprintf(fo, s_file_head_str, input_name, cmdline, ctime(&now));
+
+	/* Get an idea how many we have and restructure the tables */
+	count_resources(top);
+
+	/* First write the segment tables */
+	if(create_dir)
+	{
+		if(win32)
+			write_pe_segment(fo, top);
+		else
+			write_ne_segment(fo, top);
+	}
+
+	/* Dump the names */
+	write_rsc_names(fo, top);
+	
+	if(!indirect_only)
+	{
+		/* Write the resource data */
+		fprintf(fo, "#\n# Resource binary data\n#\n");
+		for(rsc = top; rsc; rsc = rsc->next)
+		{
+			if(!rsc->binres)
+				continue;
+
+			fprintf(fo, "\t.align\t%d\n", win32 ? 4 : alignment);
+			fprintf(fo, "%s%s_data:\n", prefix, rsc->c_name);
+			if(global)
+				fprintf(fo, "\t.globl\t%s%s_data\n", prefix, rsc->c_name);
+
+			write_s_res(fo, rsc->binres);
+
+			fprintf(fo, "\n");
+		}
+	}
+
+	if(indirect)
+	{
+		/* Write the indirection structures */
+		fprintf(fo, "\n#\n# Resource indirection structures\n#\n");
+		fprintf(fo, "\t.align\t4\n");
+		for(rsc = top; rsc; rsc = rsc->next)
+		{
+			int type;
+			char *type_name = NULL;
+
+			if(!rsc->binres)
+				continue;
+
+			switch(rsc->type)
+			{
+			case res_menex:
+				type = WRC_RT_MENU;
+				break;
+			case res_dlgex:
+				type = WRC_RT_DIALOG;
+				break;
+			case res_usr:
+				assert(rsc->res.usr->type != NULL);
+				type_name = prep_nid_for_label(rsc->res.usr->type);
+				type = 0;
+				break;
+			default:
+				type = rsc->type;
+			}
+
+			/*
+			 * This follows a structure like:
+			 * struct wrc_resource {
+			 * 	INT32	id;
+			 *	RSCNAME	*resname;
+			 *	INT32	restype;
+			 *	RSCNAME	*typename;
+			 *	void	*data;
+			 *	UINT32	datasize;
+			 * };
+			 * The 'RSCNAME' is a pascal-style string where the
+			 * first byte/word denotes the size and the rest the string
+			 * itself.
+			 */
+			fprintf(fo, "%s%s:\n", prefix, rsc->c_name);
+			if(global)
+				fprintf(fo, "\t.globl\t%s%s\n", prefix, rsc->c_name);
+			fprintf(fo, "\t.long\t%d, %s%s%s, %d, %s%s%s%s, %s%s_data, %d\n",
+				rsc->name->type == name_ord ? rsc->name->name.i_name : 0,
+				rsc->name->type == name_ord ? "0" : prefix,
+				rsc->name->type == name_ord ? "" : rsc->c_name,
+				rsc->name->type == name_ord ? "" : "_name",
+				type,
+				type ? "0" : prefix,
+				type ? "" : "_",
+				type ? "" : type_name,
+				type ? "" : "_typename",
+				prefix,
+				rsc->c_name,
+				rsc->binres->size - rsc->binres->dataidx);
+			fprintf(fo, "\n");
+		}
+		fprintf(fo, "\n");
+
+		/* Write the indirection table */
+		fprintf(fo, "#\n# Resource indirection table\n#\n");
+		fprintf(fo, "\t.align\t4\n");
+		fprintf(fo, "%s%s:\n", prefix, _ResTable);
+		fprintf(fo, "\t.globl\t%s%s\n", prefix, _ResTable);
+		for(rsc = top; rsc; rsc = rsc->next)
+		{
+			fprintf(fo, "\t.long\t%s%s\n", prefix, rsc->c_name);
+		}
+		fprintf(fo, "\t.long\t0\n");
+		fprintf(fo, "\n");
+	}
+
+	fprintf(fo, s_file_tail_str);
+	fclose(fo);
+}
+
+/*
+ *****************************************************************************
+ * Function	: write_h_file
+ * Syntax	: void write_h_file(char *outname, resource_t *top)
+ * Input	:
+ *	outname	- Filename to write to
+ *	top	- The resource-tree to convert
+ * Output	:
+ * Description	:
+ * Remarks	:
+ *****************************************************************************
+*/
+void write_h_file(char *outname, resource_t *top)
+{
+	FILE *fo;
+	resource_t *rsc;
+	char *h_prefix;
+	int cnameidx;
+
+	if(prefix[0] == '_')
+	{
+		h_prefix = prefix + 1;
+		cnameidx = 0;
+	}
+	else if(prefix[0] == '\0')
+	{
+		h_prefix = prefix;
+		cnameidx = 1;
+	}
+	else
+	{
+		h_prefix = prefix;
+		cnameidx = 0;
+		warning("Resources might not be visible in c-namespace (missing '_' in prefix)\n");
+	}
+
+	fo = fopen(outname, "wt");
+	if(!fo)
+	{
+		error("Could not open %s\n", outname);
+	}
+
+	time(&now);
+	fprintf(fo, h_file_head_str, input_name, cmdline, ctime(&now), now, now);
+
+	/* First write the segment tables reference */
+	if(create_dir)
+	{
+		fprintf(fo, "extern %schar %s%s[];\n\n",
+			constant ? "const " : "",
+			h_prefix,
+			(win32 ? _PEResTab : _NEResTab) + cnameidx);
+	}
+
+	/* Write the resource data */
+	for(rsc = top; global && rsc; rsc = rsc->next)
+	{
+		if(!rsc->binres)
+			continue;
+
+		fprintf(fo, "extern %schar %s%s_data[];\n",
+			constant ? "const " : "",
+			h_prefix,
+			rsc->c_name + cnameidx);
+	}
+
+	if(indirect)
+	{
+		if(global)
+			fprintf(fo, "\n");
+
+		/* Write the indirection structures */
+		for(rsc = top; global && rsc; rsc = rsc->next)
+		{
+			fprintf(fo, "extern %swrc_resource%d_t %s%s;\n",
+				constant ? "const " : "",
+				win32 ? 32 : 16,
+				h_prefix,
+				rsc->c_name + cnameidx);
+		}
+
+		if(global)
+			fprintf(fo, "\n");
+
+		/* Write the indirection table */
+		fprintf(fo, "extern %swrc_resource%d_t %s%s[];\n\n",
+			constant ? "const " : "",
+			win32 ? 32 : 16,
+			h_prefix,
+			_ResTable + cnameidx);
+	}
+
+	fprintf(fo, h_file_tail_str);
+	fclose(fo);
+}
+
+
diff --git a/tools/wrc/writeres.h b/tools/wrc/writeres.h
new file mode 100644
index 0000000..08da1b2
--- /dev/null
+++ b/tools/wrc/writeres.h
@@ -0,0 +1,19 @@
+/*
+ * Write resource prototypes
+ *
+ * Copyright 1998 Bertho A. Stultiens (BS)
+ *
+ */
+
+#ifndef __WRC_WRITERES_H
+#define __WRC_WRITERES_H
+
+#ifndef __WRC_WRCTYPES_H
+#include "wrctypes.h"
+#endif
+
+void write_resfile(char *outname, resource_t *top);
+void write_s_file(char *outname, resource_t *top);
+void write_h_file(char *outname, resource_t *top);
+
+#endif