First stab at Windows resource compiler:
authorIan Lance Taylor <ian@airs.com>
Sun, 22 Jun 1997 21:35:35 +0000 (21:35 +0000)
committerIan Lance Taylor <ian@airs.com>
Sun, 22 Jun 1997 21:35:35 +0000 (21:35 +0000)
* windres.h: New file.
* windres.c: New file.
* resrc.c: New file.
* rcparse.y: New file.
* rclex.l: New file.
* configure.in: Define and substitute BUILD_WINDRES.
* configure: Rebuild.
* Makefile.in: Rebuild dependencies.
  (WINDRES_PROG): New variable.
(PROGS): Add @BUILD_WINDRES@.
(HFILES): Add dlltool.h and windres.h.
(CFILES): Add windres.c and resrc.c.
(GENERATED_CFILES): Add rcparse.c and rclex.c.
(WINDRES_OBJS): New variable.
$(WINDRES_PROG): New target.
(rcparse.c, rcparse.h, rclex.c): New targets.
Snapshot.  windres can parse and print rc files.

binutils/.Sanitize
binutils/ChangeLog
binutils/Makefile.in
binutils/configure
binutils/configure.in
binutils/rclex.l [new file with mode: 0644]
binutils/rcparse.y [new file with mode: 0644]
binutils/resrc.c [new file with mode: 0644]
binutils/windres.c [new file with mode: 0644]
binutils/windres.h [new file with mode: 0644]

index f253b50..5bae795 100644 (file)
@@ -82,6 +82,9 @@ objdump.c
 prdbg.c
 ranlib.1
 ranlib.sh
+rclex.l
+rcparse.y
+resrc.c
 rdcoff.c
 rddbg.c
 sanity.sh
@@ -98,6 +101,8 @@ syslex.l
 sysroff.info
 testsuite
 version.c
+windres.h
+windres.c
 wrstabs.c
 
 Things-to-lose:
index 1ab9055..2a685dc 100644 (file)
@@ -1,3 +1,23 @@
+Sun Jun 22 17:29:41 1997  Ian Lance Taylor  <ian@cygnus.com>
+
+       First stab at Windows resource compiler:
+       * windres.h: New file.
+       * windres.c: New file.
+       * resrc.c: New file.
+       * rcparse.y: New file.
+       * rclex.l: New file.
+       * configure.in: Define and substitute BUILD_WINDRES.
+       * configure: Rebuild.
+       * Makefile.in: Rebuild dependencies.
+       (WINDRES_PROG): New variable.
+       (PROGS): Add @BUILD_WINDRES@.
+       (HFILES): Add dlltool.h and windres.h.
+       (CFILES): Add windres.c and resrc.c.
+       (GENERATED_CFILES): Add rcparse.c and rclex.c.
+       (WINDRES_OBJS): New variable.
+       $(WINDRES_PROG): New target.
+       (rcparse.c, rcparse.h, rclex.c): New targets.
+
 Thu Jun 12 12:27:51 1997  Ian Lance Taylor  <ian@cygnus.com>
 
        * dlltool.c (export_type): Add data field.
index 985e226..65d25f7 100644 (file)
@@ -103,12 +103,13 @@ ADDR2LINE_PROG=addr2line
 
 NLMCONV_PROG=nlmconv
 DLLTOOL_PROG=dlltool
+WINDRES_PROG=windres
 
 SRCONV_PROG=srconv sysdump coffdump 
 
 MANPAGES= ar nm objdump ranlib size strings strip objcopy addr2line nlmconv
 
-PROGS = $(SIZE_PROG) $(OBJDUMP_PROG) $(NM_PROG) $(AR_PROG) $(STRINGS_PROG) $(STRIP_PROG) $(RANLIB_PROG) $(DEMANGLER_PROG) $(OBJCOPY_PROG) $(ADDR2LINE_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@
+PROGS = $(SIZE_PROG) $(OBJDUMP_PROG) $(NM_PROG) $(AR_PROG) $(STRINGS_PROG) $(STRIP_PROG) $(RANLIB_PROG) $(DEMANGLER_PROG) $(OBJCOPY_PROG) $(ADDR2LINE_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@
 STAGESTUFF = $(PROGS) *.o
 # Files that can be generated, but should be in the distribution.
 # Don't build $(DEMANGLER_PROG).1, since its name may vary with the
@@ -127,7 +128,8 @@ DEP = mkdep
 
 ALL_CFLAGS = -D_GNU_SOURCE $(INCLUDES) @HDEFINES@ $(CFLAGS)
 
-HFILES = arsup.h bucomm.h budbg.h coffgrok.h debug.h nlmconv.h
+HFILES = arsup.h bucomm.h budbg.h coffgrok.h debug.h nlmconv.h dlltool.h \
+       windres.h
 
 GENERATED_HFILES = arparse.h sysroff.h sysinfo.h defparse.h
 
@@ -135,11 +137,12 @@ CFILES = addr2line.c ar.c arsup.c bucomm.c coffdump.c coffgrok.c debug.c \
        dlltool.c filemode.c ieee.c is-ranlib.c is-strip.c maybe-ranlib.c \
        maybe-strip.c nlmconv.c nm.c not-ranlib.c not-strip.c \
        objcopy.c objdump.c prdbg.c rdcoff.c rddbg.c size.c srconv.c \
-       stabs.c strings.c sysdump.c version.c wrstabs.c
+       stabs.c strings.c sysdump.c version.c wrstabs.c \
+       windres.c resrc.c
 
 GENERATED_CFILES = \
        underscore.c arparse.c arlex.c sysroff.c sysinfo.c syslex.c \
-       defparse.c deflex.c nlmheader.c
+       defparse.c deflex.c nlmheader.c rcparse.c rclex.c
 
 .c.o:
        $(CC) -c $(ALL_CFLAGS) $<
@@ -235,7 +238,7 @@ check: site.exp
           TCL_LIBRARY=$${srcroot}/../tcl/library ; \
           export TCL_LIBRARY ; else true; fi ; \
        $(RUNTEST) --tool binutils --srcdir $(srcdir)/testsuite \
-         $(RUNTESTFLAGS) CC="$(CC_FOR_TARGET)" CFLAGS="$(CFLAGS)"
+         $(RUNTESTFLAGS) CC_FOR_TARGET="$(CC_FOR_TARGET)" CFLAGS_FOR_TARGET="$(CFLAGS)"
 
 installcheck:
        /bin/sh $(srcdir)/sanity.sh $(bindir)
@@ -406,6 +409,26 @@ nlmconv.o: nlmconv.c $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h
 $(NLMCONV_PROG): nlmconv.o nlmheader.o $(ADDL_DEPS)
        $(HLDENV) $(CC) $(HLDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ nlmconv.o nlmheader.o $(ADDL_LIBS) $(EXTRALIBS)
 
+WINDRES_OBJS = windres.o resrc.o rcparse.o rclex.o
+
+$(WINDRES_PROG): $(WINDRES_OBJS) $(ADDL_DEPS)
+       $(HLDENV) $(CC) $(HLDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(WINDRES_OBJS) $(ADDL_LIBS) $(EXTRALIBS)
+
+# Depend upon defparse.c to avoid building both defparse.c and
+# rcparse.c simultaneously.
+rcparse.c: rcparse.y defparse.c
+       $(BISON) $(BISONFLAGS) $(srcdir)/rcparse.y
+       mv -f y.tab.c rcparse.c
+       mv -f y.tab.h rcparse.h
+
+rcparse.h: rcparse.c
+
+# Depend upon deflex.c to avoid building both deflex.c and rclex.c
+# simultaneously.
+rclex.c: rclex.l deflex.c
+       $(LEX) $(LEX_OPTIONS) $(srcdir)/rclex.l
+       mv lex.yy.c rclex.c
+
 # Targets to rebuild dependencies in this Makefile.
 # Have to get rid of .dep1 here so that "$?" later includes all of $(CFILES).
 .dep: dep.sed $(CFILES) $(HFILES) $(GENERATED_CFILES) $(GENERATED_HFILES) config.h
@@ -533,7 +556,7 @@ distclean:
 maintainer-clean realclean: clean distclean
        @echo "This command is intended for maintainers to use;"
        @echo "it deletes files that may require special tools to rebuild."
-       -rm -f $(DISTSTUFF) *.info* TAGS
+       -rm -f $(DISTSTUFF) binutils.info* TAGS
 
 etags tags: TAGS
 
@@ -680,7 +703,7 @@ debug.o: debug.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   debug.h
 dlltool.o: dlltool.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   $(INCDIR)/libiberty.h bucomm.h config.h $(INCDIR)/fopen-same.h \
-  $(INCDIR)/getopt.h $(INCDIR)/demangle.h
+  $(INCDIR)/getopt.h $(INCDIR)/demangle.h dlltool.h
 filemode.o: filemode.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   bucomm.h config.h $(INCDIR)/fopen-same.h
 ieee.o: ieee.c ../bfd/bfd.h $(INCDIR)/ansidecl.h $(INCDIR)/ieee.h \
@@ -737,6 +760,12 @@ wrstabs.o: wrstabs.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \
   debug.h budbg.h $(INCDIR)/aout/aout64.h $(INCDIR)/aout/stab_gnu.h \
   $(INCDIR)/aout/stab.def
+windres.o: windres.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
+  $(INCDIR)/getopt.h bucomm.h config.h $(INCDIR)/fopen-same.h \
+  $(INCDIR)/libiberty.h windres.h
+resrc.o: resrc.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
+  bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \
+  windres.h
 underscore.o: underscore.c
 arparse.o: arparse.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   bucomm.h config.h $(INCDIR)/fopen-same.h arsup.h
@@ -744,10 +773,18 @@ arlex.o: arlex.c $(INCDIR)/libiberty.h arparse.h
 sysroff.o: sysroff.c
 sysinfo.o: sysinfo.c
 syslex.o: syslex.c sysinfo.h
-defparse.o: defparse.c
-deflex.o: deflex.c defparse.h
+defparse.o: defparse.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
+  bucomm.h config.h $(INCDIR)/fopen-same.h dlltool.h
+deflex.o: deflex.c $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h \
+  defparse.h dlltool.h
 nlmheader.o: nlmheader.c ../bfd/bfd.h bucomm.h config.h \
   $(INCDIR)/fopen-same.h $(INCDIR)/nlm/common.h $(INCDIR)/nlm/internal.h \
   nlmconv.h
+rcparse.o: rcparse.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
+  bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \
+  windres.h
+rclex.o: rclex.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
+  bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \
+  windres.h rcparse.h
 
 # IF YOU PUT ANYTHING HERE IT WILL GO AWAY
index 066b290..57ba36e 100755 (executable)
@@ -1006,8 +1006,13 @@ esac
 
 if test "${commonbfdlib}" = "true"; then
   # when a shared libbfd is built with --enable-commonbfdlib,
-  # all of libopcodes is available in libbfd.so
-  OPCODES=
+  # all of libopcodes is available in libbfd.so.  Unfortunately, on
+  # HP/UX, when using gcc -g, the linker does a static link, so we
+  # need to continue linking against opcodes on that platform.
+  case "${host}" in
+  *-*-hpux*) ;;
+  *) OPCODES= ;;
+  esac
 fi
 
 
@@ -1024,7 +1029,7 @@ fi
 
 
 echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:1028: checking how to run the C preprocessor" >&5
+echo "configure:1033: checking how to run the C preprocessor" >&5
 # On Suns, sometimes $CPP names a directory.
 if test -n "$CPP" && test -d "$CPP"; then
   CPP=
@@ -1039,13 +1044,13 @@ else
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp.
   cat > conftest.$ac_ext <<EOF
-#line 1043 "configure"
+#line 1048 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1049: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1054: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   :
@@ -1056,13 +1061,13 @@ else
   rm -rf conftest*
   CPP="${CC-cc} -E -traditional-cpp"
   cat > conftest.$ac_ext <<EOF
-#line 1060 "configure"
+#line 1065 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1066: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1071: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   :
@@ -1088,17 +1093,17 @@ for ac_hdr in string.h strings.h stdlib.h unistd.h fcntl.h sys/file.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1092: checking for $ac_hdr" >&5
+echo "configure:1097: checking for $ac_hdr" >&5
 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1097 "configure"
+#line 1102 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1102: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1107: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1125,12 +1130,12 @@ fi
 done
 
 echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
-echo "configure:1129: checking for sys/wait.h that is POSIX.1 compatible" >&5
+echo "configure:1134: checking for sys/wait.h that is POSIX.1 compatible" >&5
 if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1134 "configure"
+#line 1139 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -1146,7 +1151,7 @@ wait (&s);
 s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
 ; return 0; }
 EOF
-if { (eval echo configure:1150: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1155: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_header_sys_wait_h=yes
 else
@@ -1169,19 +1174,19 @@ fi
 # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
 # for constant arguments.  Useless!
 echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
-echo "configure:1173: checking for working alloca.h" >&5
+echo "configure:1178: checking for working alloca.h" >&5
 if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1178 "configure"
+#line 1183 "configure"
 #include "confdefs.h"
 #include <alloca.h>
 int main() {
 char *p = alloca(2 * sizeof(int));
 ; return 0; }
 EOF
-if { (eval echo configure:1185: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1190: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   ac_cv_header_alloca_h=yes
 else
@@ -1202,12 +1207,12 @@ EOF
 fi
 
 echo $ac_n "checking for alloca""... $ac_c" 1>&6
-echo "configure:1206: checking for alloca" >&5
+echo "configure:1211: checking for alloca" >&5
 if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1211 "configure"
+#line 1216 "configure"
 #include "confdefs.h"
 
 #ifdef __GNUC__
@@ -1230,7 +1235,7 @@ int main() {
 char *p = (char *) alloca(1);
 ; return 0; }
 EOF
-if { (eval echo configure:1234: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1239: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   ac_cv_func_alloca_works=yes
 else
@@ -1262,12 +1267,12 @@ EOF
 
 
 echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
-echo "configure:1266: checking whether alloca needs Cray hooks" >&5
+echo "configure:1271: checking whether alloca needs Cray hooks" >&5
 if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1271 "configure"
+#line 1276 "configure"
 #include "confdefs.h"
 #if defined(CRAY) && ! defined(CRAY2)
 webecray
@@ -1292,12 +1297,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&6
 if test $ac_cv_os_cray = yes; then
 for ac_func in _getb67 GETB67 getb67; do
   echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1296: checking for $ac_func" >&5
+echo "configure:1301: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1301 "configure"
+#line 1306 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -1320,7 +1325,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1324: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1329: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -1347,7 +1352,7 @@ done
 fi
 
 echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
-echo "configure:1351: checking stack direction for C alloca" >&5
+echo "configure:1356: checking stack direction for C alloca" >&5
 if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1355,7 +1360,7 @@ else
   ac_cv_c_stack_direction=0
 else
   cat > conftest.$ac_ext <<EOF
-#line 1359 "configure"
+#line 1364 "configure"
 #include "confdefs.h"
 find_stack_direction ()
 {
@@ -1374,7 +1379,7 @@ main ()
   exit (find_stack_direction() < 0);
 }
 EOF
-if { (eval echo configure:1378: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1383: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
 then
   ac_cv_c_stack_direction=1
 else
@@ -1398,12 +1403,12 @@ fi
 for ac_func in sbrk utimes
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1402: checking for $ac_func" >&5
+echo "configure:1407: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1407 "configure"
+#line 1412 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -1426,7 +1431,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1430: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1435: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -1452,12 +1457,12 @@ done
 
 if test "x$cross_compiling" = "xno"; then
   echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1456: checking for ANSI C header files" >&5
+echo "configure:1461: checking for ANSI C header files" >&5
 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1461 "configure"
+#line 1466 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -1465,7 +1470,7 @@ else
 #include <float.h>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1469: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1474: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1482,7 +1487,7 @@ rm -f conftest*
 if test $ac_cv_header_stdc = yes; then
   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1486 "configure"
+#line 1491 "configure"
 #include "confdefs.h"
 #include <string.h>
 EOF
@@ -1500,7 +1505,7 @@ fi
 if test $ac_cv_header_stdc = yes; then
   # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1504 "configure"
+#line 1509 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -1521,7 +1526,7 @@ if test "$cross_compiling" = yes; then
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 1525 "configure"
+#line 1530 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1532,7 +1537,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
 exit (0); }
 
 EOF
-if { (eval echo configure:1536: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1541: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
 then
   :
 else
@@ -1556,12 +1561,12 @@ EOF
 fi
 
 echo $ac_n "checking for pid_t""... $ac_c" 1>&6
-echo "configure:1560: checking for pid_t" >&5
+echo "configure:1565: checking for pid_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1565 "configure"
+#line 1570 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -1590,17 +1595,17 @@ fi
 
 ac_safe=`echo "vfork.h" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for vfork.h""... $ac_c" 1>&6
-echo "configure:1594: checking for vfork.h" >&5
+echo "configure:1599: checking for vfork.h" >&5
 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1599 "configure"
+#line 1604 "configure"
 #include "confdefs.h"
 #include <vfork.h>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1604: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1609: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1625,18 +1630,18 @@ else
 fi
 
 echo $ac_n "checking for working vfork""... $ac_c" 1>&6
-echo "configure:1629: checking for working vfork" >&5
+echo "configure:1634: checking for working vfork" >&5
 if eval "test \"`echo '$''{'ac_cv_func_vfork_works'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   if test "$cross_compiling" = yes; then
   echo $ac_n "checking for vfork""... $ac_c" 1>&6
-echo "configure:1635: checking for vfork" >&5
+echo "configure:1640: checking for vfork" >&5
 if eval "test \"`echo '$''{'ac_cv_func_vfork'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1640 "configure"
+#line 1645 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char vfork(); below.  */
@@ -1659,7 +1664,7 @@ vfork();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1663: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1668: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   eval "ac_cv_func_vfork=yes"
 else
@@ -1680,7 +1685,7 @@ fi
 
 else
   cat > conftest.$ac_ext <<EOF
-#line 1684 "configure"
+#line 1689 "configure"
 #include "confdefs.h"
 /* Thanks to Paul Eggert for this test.  */
 #include <stdio.h>
@@ -1775,7 +1780,7 @@ main() {
   }
 }
 EOF
-if { (eval echo configure:1779: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1784: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
 then
   ac_cv_func_vfork_works=yes
 else
@@ -1799,12 +1804,12 @@ fi
 
 else
   echo $ac_n "checking for vfork""... $ac_c" 1>&6
-echo "configure:1803: checking for vfork" >&5
+echo "configure:1808: checking for vfork" >&5
 if eval "test \"`echo '$''{'ac_cv_func_vfork'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1808 "configure"
+#line 1813 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char vfork(); below.  */
@@ -1827,7 +1832,7 @@ vfork();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1831: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1836: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   eval "ac_cv_func_vfork=yes"
 else
@@ -1853,19 +1858,19 @@ fi
 fi
 
 echo $ac_n "checking for time_t in time.h""... $ac_c" 1>&6
-echo "configure:1857: checking for time_t in time.h" >&5
+echo "configure:1862: checking for time_t in time.h" >&5
 if eval "test \"`echo '$''{'bu_cv_decl_time_t_time_h'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1862 "configure"
+#line 1867 "configure"
 #include "confdefs.h"
 #include <time.h>
 int main() {
 time_t i;
 ; return 0; }
 EOF
-if { (eval echo configure:1869: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1874: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   bu_cv_decl_time_t_time_h=yes
 else
@@ -1886,19 +1891,19 @@ EOF
 fi
 
 echo $ac_n "checking for time_t in sys/types.h""... $ac_c" 1>&6
-echo "configure:1890: checking for time_t in sys/types.h" >&5
+echo "configure:1895: checking for time_t in sys/types.h" >&5
 if eval "test \"`echo '$''{'bu_cv_decl_time_t_types_h'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1895 "configure"
+#line 1900 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 int main() {
 time_t i;
 ; return 0; }
 EOF
-if { (eval echo configure:1902: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1907: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   bu_cv_decl_time_t_types_h=yes
 else
@@ -1921,12 +1926,12 @@ fi
 # Under Next 3.2 <utime.h> apparently does not define struct utimbuf
 # by default.
 echo $ac_n "checking for utime.h""... $ac_c" 1>&6
-echo "configure:1925: checking for utime.h" >&5
+echo "configure:1930: checking for utime.h" >&5
 if eval "test \"`echo '$''{'bu_cv_header_utime_h'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1930 "configure"
+#line 1935 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #ifdef HAVE_TIME_H
@@ -1937,7 +1942,7 @@ int main() {
 struct utimbuf s;
 ; return 0; }
 EOF
-if { (eval echo configure:1941: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1946: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   bu_cv_header_utime_h=yes
 else
@@ -1958,12 +1963,12 @@ EOF
 fi
 
 echo $ac_n "checking whether fprintf must be declared""... $ac_c" 1>&6
-echo "configure:1962: checking whether fprintf must be declared" >&5
+echo "configure:1967: checking whether fprintf must be declared" >&5
 if eval "test \"`echo '$''{'bfd_cv_decl_needed_fprintf'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1967 "configure"
+#line 1972 "configure"
 #include "confdefs.h"
 
 #include <stdio.h>
@@ -1984,7 +1989,7 @@ int main() {
 char *(*pfn) = (char *(*)) fprintf
 ; return 0; }
 EOF
-if { (eval echo configure:1988: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1993: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   bfd_cv_decl_needed_fprintf=no
 else
@@ -2006,12 +2011,12 @@ EOF
 fi
 
 echo $ac_n "checking whether strstr must be declared""... $ac_c" 1>&6
-echo "configure:2010: checking whether strstr must be declared" >&5
+echo "configure:2015: checking whether strstr must be declared" >&5
 if eval "test \"`echo '$''{'bfd_cv_decl_needed_strstr'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2015 "configure"
+#line 2020 "configure"
 #include "confdefs.h"
 
 #include <stdio.h>
@@ -2032,7 +2037,7 @@ int main() {
 char *(*pfn) = (char *(*)) strstr
 ; return 0; }
 EOF
-if { (eval echo configure:2036: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2041: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   bfd_cv_decl_needed_strstr=no
 else
@@ -2054,12 +2059,12 @@ EOF
 fi
 
 echo $ac_n "checking whether sbrk must be declared""... $ac_c" 1>&6
-echo "configure:2058: checking whether sbrk must be declared" >&5
+echo "configure:2063: checking whether sbrk must be declared" >&5
 if eval "test \"`echo '$''{'bfd_cv_decl_needed_sbrk'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2063 "configure"
+#line 2068 "configure"
 #include "confdefs.h"
 
 #include <stdio.h>
@@ -2080,7 +2085,7 @@ int main() {
 char *(*pfn) = (char *(*)) sbrk
 ; return 0; }
 EOF
-if { (eval echo configure:2084: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2089: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   bfd_cv_decl_needed_sbrk=no
 else
@@ -2102,12 +2107,12 @@ EOF
 fi
 
 echo $ac_n "checking whether getenv must be declared""... $ac_c" 1>&6
-echo "configure:2106: checking whether getenv must be declared" >&5
+echo "configure:2111: checking whether getenv must be declared" >&5
 if eval "test \"`echo '$''{'bfd_cv_decl_needed_getenv'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2111 "configure"
+#line 2116 "configure"
 #include "confdefs.h"
 
 #include <stdio.h>
@@ -2128,7 +2133,7 @@ int main() {
 char *(*pfn) = (char *(*)) getenv
 ; return 0; }
 EOF
-if { (eval echo configure:2132: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2137: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   bfd_cv_decl_needed_getenv=no
 else
@@ -2165,7 +2170,7 @@ esac
 if test -n "$enable_targets"; then
     for targ in `echo $enable_targets | sed 's/,/ /g'`
     do
-       result=`$ac_config_sub $targ 2>/dev/null`
+       result=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $targ 2>/dev/null`
        if test -n "$result"; then
            canon_targets="$canon_targets $result"
        else
@@ -2181,6 +2186,7 @@ NLMCONV_DEFS=
 BUILD_SRCONV=
 BUILD_DLLTOOL=
 DLLTOOL_DEFS=
+BUILD_WINDRES=
 
 for targ in $target $canon_targets
 do
@@ -2215,14 +2221,17 @@ do
        arm-*pe*)
          BUILD_DLLTOOL='$(DLLTOOL_PROG)'
          DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_ARM"
+         BUILD_WINDRES='$(WINDRES_PROG)'
         ;;
        i[3-6]86-*pe* | i[3-6]86-*-cygwin32)
          BUILD_DLLTOOL='$(DLLTOOL_PROG)'
          DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_I386"
+         BUILD_WINDRES='$(WINDRES_PROG)'
         ;;
        powerpc*-*-*pe* | powerpc*-*-cygwin32)
          BUILD_DLLTOOL='$(DLLTOOL_PROG)'
          DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_PPC"
+         BUILD_WINDRES='$(WINDRES_PROG)'
         ;;
        esac
     fi
@@ -2234,6 +2243,7 @@ done
 
 
 
+
 targ=$target
 . $srcdir/../bfd/config.bfd
 if test "x$targ_underscore" = "xyes"; then
@@ -2408,6 +2418,7 @@ s%@BUILD_NLMCONV@%$BUILD_NLMCONV%g
 s%@BUILD_SRCONV@%$BUILD_SRCONV%g
 s%@BUILD_DLLTOOL@%$BUILD_DLLTOOL%g
 s%@DLLTOOL_DEFS@%$DLLTOOL_DEFS%g
+s%@BUILD_WINDRES@%$BUILD_WINDRES%g
 s%@UNDERSCORE@%$UNDERSCORE%g
 
 CEOF
index f5ce9d6..67fdb06 100644 (file)
@@ -98,8 +98,13 @@ esac
 
 if test "${commonbfdlib}" = "true"; then
   # when a shared libbfd is built with --enable-commonbfdlib,
-  # all of libopcodes is available in libbfd.so
-  OPCODES=
+  # all of libopcodes is available in libbfd.so.  Unfortunately, on
+  # HP/UX, when using gcc -g, the linker does a static link, so we
+  # need to continue linking against opcodes on that platform.
+  case "${host}" in
+  *-*-hpux*) ;;
+  *) OPCODES= ;;
+  esac
 fi
 
 AC_SUBST(BFDLIB)
@@ -166,7 +171,7 @@ BFD_BINARY_FOPEN
 if test -n "$enable_targets"; then
     for targ in `echo $enable_targets | sed 's/,/ /g'`
     do
-       result=`$ac_config_sub $targ 2>/dev/null`
+       result=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $targ 2>/dev/null`
        if test -n "$result"; then
            canon_targets="$canon_targets $result"
        else
@@ -182,6 +187,7 @@ NLMCONV_DEFS=
 BUILD_SRCONV=
 BUILD_DLLTOOL=
 DLLTOOL_DEFS=
+BUILD_WINDRES=
 
 for targ in $target $canon_targets
 do
@@ -218,16 +224,19 @@ changequote([,])dnl
        arm-*pe*)
          BUILD_DLLTOOL='$(DLLTOOL_PROG)'
          DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_ARM"
+         BUILD_WINDRES='$(WINDRES_PROG)'
         ;;
 changequote(,)dnl
        i[3-6]86-*pe* | i[3-6]86-*-cygwin32)
 changequote([,])dnl
          BUILD_DLLTOOL='$(DLLTOOL_PROG)'
          DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_I386"
+         BUILD_WINDRES='$(WINDRES_PROG)'
         ;;
        powerpc*-*-*pe* | powerpc*-*-cygwin32)
          BUILD_DLLTOOL='$(DLLTOOL_PROG)'
          DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_PPC"
+         BUILD_WINDRES='$(WINDRES_PROG)'
         ;;
        esac
     fi
@@ -238,6 +247,7 @@ AC_SUBST(BUILD_NLMCONV)
 AC_SUBST(BUILD_SRCONV)
 AC_SUBST(BUILD_DLLTOOL)
 AC_SUBST(DLLTOOL_DEFS)
+AC_SUBST(BUILD_WINDRES)
 
 targ=$target
 . $srcdir/../bfd/config.bfd
diff --git a/binutils/rclex.l b/binutils/rclex.l
new file mode 100644 (file)
index 0000000..eb36bf6
--- /dev/null
@@ -0,0 +1,320 @@
+%{ /* rclex.l -- lexer for Windows rc files parser  */
+/* Copyright 1997 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support.
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* This is a lex input file which generates a lexer used by the
+   Windows rc file parser.  It basically just recognized a bunch of
+   keywords.  */
+
+#include "bfd.h"
+#include "bucomm.h"
+#include "libiberty.h"
+#include "windres.h"
+#include "rcparse.h"
+
+#include <ctype.h>
+#include <assert.h>
+
+static void cpp_line PARAMS ((const char *));
+static char *handle_quotes PARAMS ((const char *));
+
+%}
+
+%%
+
+"BEGIN"                        { return BEG; }
+"END"                  { return END; }
+"ACCELERATORS"         { return ACCELERATORS; }
+"VIRTKEY"              { return VIRTKEY; }
+"ASCII"                        { return ASCII; }
+"NOINVERT"             { return NOINVERT; }
+"SHIFT"                        { return SHIFT; }
+"CONTROL"              { return CONTROL; }
+"ALT"                  { return ALT; }
+"BITMAP"               { return BITMAP; }
+"CURSOR"               { return CURSOR; }
+"DIALOG"               { return DIALOG; }
+"DIALOGEX"             { return DIALOGEX; }
+"EXSTYLE"              { return EXSTYLE; }
+"CAPTION"              { return CAPTION; }
+"CLASS"                        { return CLASS; }
+"STYLE"                        { return STYLE; }
+"AUTO3STATE"           { return AUTO3STATE; }
+"AUTOCHECKBOX"         { return AUTOCHECKBOX; }
+"AUTORADIOBUTTON"      { return AUTORADIOBUTTON; }
+"CHECKBOX"             { return CHECKBOX; }
+"COMBOBOX"             { return COMBOBOX; }
+"CTEXT"                        { return CTEXT; }
+"DEFPUSHBUTTON"                { return DEFPUSHBUTTON; }
+"EDITTEXT"             { return EDITTEXT; }
+"GROUPBOX"             { return GROUPBOX; }
+"LISTBOX"              { return LISTBOX; }
+"LTEXT"                        { return LTEXT; }
+"PUSHBOX"              { return PUSHBOX; }
+"PUSHBUTTON"           { return PUSHBUTTON; }
+"RADIOBUTTON"          { return RADIOBUTTON; }
+"RTEXT"                        { return RTEXT; }
+"SCROLLBAR"            { return SCROLLBAR; }
+"STATE3"               { return STATE3; }
+"USERBUTTON"           { return USERBUTTON; }
+"BEDIT"                        { return BEDIT; }
+"HEDIT"                        { return HEDIT; }
+"IEDIT"                        { return IEDIT; }
+"FONT"                 { return FONT; }
+"ICON"                 { return ICON; }
+"LANGUAGE"             { return LANGUAGE; }
+"CHARACTERISTICS"      { return CHARACTERISTICS; }
+"VERSION"              { return VERSION; }
+"MENU"                 { return MENU; }
+"MENUEX"               { return MENUEX; }
+"MENUITEM"             { return MENUITEM; }
+"SEPARATOR"            { return SEPARATOR; }
+"POPUP"                        { return POPUP; }
+"CHECKED"              { return CHECKED; }
+"GRAYED"               { return GRAYED; }
+"HELP"                 { return HELP; }
+"INACTIVE"             { return INACTIVE; }
+"MENUBARBREAK"         { return MENUBARBREAK; }
+"MENUBREAK"            { return MENUBREAK; }
+"MESSAGETABLE"         { return MESSAGETABLE; }
+"RCDATA"               { return RCDATA; }
+"STRINGTABLE"          { return STRINGTABLE; }
+"VERSIONINFO"          { return VERSIONINFO; }
+"FILEVERSION"          { return FILEVERSION; }
+"PRODUCTVERSION"       { return PRODUCTVERSION; }
+"FILEFLAGSMASK"                { return FILEFLAGSMASK; }
+"FILEFLAGS"            { return FILEFLAGS; }
+"FILEOS"               { return FILEOS; }
+"FILETYPE"             { return FILETYPE; }
+"FILESUBTYPE"          { return FILESUBTYPE; }
+"VALUE"                        { return VALUE; }
+"MOVEABLE"             { return MOVEABLE; }
+"FIXED"                        { return FIXED; }
+"PURE"                 { return PURE; }
+"IMPURE"               { return IMPURE; }
+"PRELOAD"              { return PRELOAD; }
+"LOADONCALL"           { return LOADONCALL; }
+"DISCARDABLE"          { return DISCARDABLE; }
+"NOT"                  { return NOT; }
+
+"BLOCK"[ \t\n]*"\""[^\#\n]*"\"" {
+                         char *s, *send;
+
+                         /* This is a hack to let us parse version
+                             information easily.  */
+
+                         s = strchr (yytext, '"');
+                         ++s;
+                         send = strchr (s, '"');
+                         if (strncmp (s, "StringFileInfo",
+                                      sizeof "StringFileInfo" - 1) == 0
+                             && s + sizeof "StringFileInfo" - 1 == send)
+                           return BLOCKSTRINGFILEINFO;
+                         else if (strncmp (s, "VarFileInfo",
+                                           sizeof "VarFileInfo" - 1) == 0
+                                  && s + sizeof "VarFileInfo" - 1 == send)
+                           return BLOCKVARFILEINFO;
+                         else
+                           {
+                             yylval.s = (char *) xmalloc (send - s + 1);
+                             strncpy (yylval.s, s, send - s);
+                             yylval.s[send - s] = '\0';
+                             return BLOCK;
+                           }
+                       }
+
+"#"[^\n]*              {
+                         cpp_line (yytext);
+                       }
+
+[0-9][x0-9A-Fa-f]*L    {
+                         yylval.i.val = strtoul (yytext, 0, 0);
+                         yylval.i.dword = 1;
+                         return NUMBER;
+                       }
+
+[0-9][x0-9A-Fa-f]*     {
+                         yylval.i.val = strtoul (yytext, 0, 0);
+                         yylval.i.dword = 0;
+                         return NUMBER;
+                       }
+
+("\""[^\"\n]*"\""[ \t]*)+ {
+                         yylval.s = handle_quotes (yytext);
+                         return QUOTEDSTRING;
+                       }
+
+[A-Za-z][^ \t\r\n]*    {
+                         yylval.s = xstrdup (yytext);
+                         return STRING;
+                       }
+
+[\n]                   { ++rc_lineno; }
+[ \t\r]+               { /* ignore whitespace */ }
+.                      { return *yytext; }
+
+%%
+#ifndef yywrap
+/* This is needed for some versions of lex.  */
+int yywrap ()
+{
+  return 1;
+}
+#endif
+
+/* Handle a C preprocessor line.  */
+
+static void
+cpp_line (s)
+     const char *s;
+{
+  int line;
+  char *send, *fn;
+
+  ++s;
+  while (isspace (*s))
+    ++s;
+  
+  line = strtol (s, &send, 0);
+  if (*send != '\0' && ! isspace (*send))
+    return;
+
+  /* Subtract 1 because we are about to count the newline.  */
+  rc_lineno = line - 1;
+
+  s = send;
+  while (isspace (*s))
+    ++s;
+
+  if (*s != '"')
+    return;
+
+  ++s;
+  send = strchr (s, '"');
+  if (send == NULL)
+    return;
+
+  fn = (char *) xmalloc (send - s + 1);
+  strncpy (fn, s, send - s);
+  fn[send - s] = '\0';
+
+  free (rc_filename);
+  rc_filename = fn;
+}
+
+/* Handle a quoted string.  The quotes are stripped.  A pair of quotes
+   in a string are turned into a single quote.  Adjacent strings are
+   merged separated by whitespace are merged, as in C.  */
+
+static char *
+handle_quotes (input)
+     const char *input;
+{
+  char *ret, *s;
+  const char *t;
+  int ch;
+
+  ret = (char *) xmalloc (strlen (input) + 1);
+
+  s = ret;
+  t = input;
+  if (*t == '"')
+    ++t;
+  while (*t != '\0')
+    {
+      if (*t == '\\')
+       {
+         ++t;
+         switch (*t)
+           {
+           case '\0':
+             rcparse_warning ("backslash at end of string");
+             break;
+
+           case '\"':
+             rcparse_warning ("use \"\" to put \" in a string");
+             break;
+
+           case '\\':
+             *s++ = *t++;
+             break;
+
+           case '0': case '1': case '2': case '3':
+           case '4': case '5': case '6': case '7':
+             ch = *t - '0';
+             ++t;
+             if (*t >= '0' && *t <= '7')
+               {
+                 ch = (ch << 3) | (*t - '0');
+                 ++t;
+                 if (*t >= '0' && *t <= '7')
+                   {
+                     ch = (ch << 3) | (*t - '0');
+                     ++t;
+                   }
+               }
+             *s++ = ch;
+             break;
+
+           case 'x':
+             ++t;
+             ch = 0;
+             while (1)
+               {
+                 if (*t >= '0' && *t <= '9')
+                   ch = (ch << 4) | (*t - '0');
+                 else if (*t >= 'a' && *t <= 'f')
+                   ch = (ch << 4) | (*t - 'a');
+                 else if (*t >= 'A' && *t <= 'F')
+                   ch = (ch << 4) | (*t - 'A');
+                 else
+                   break;
+                 ++t;
+               }
+             *s++ = ch;
+             break;
+           }
+       }
+      else if (*t != '"')
+       *s++ = *t++;
+      else if (t[1] == '\0')
+       break;
+      else if (t[1] == '"')
+       {
+         *s++ = '"';
+         t += 2;
+       }
+      else
+       {
+         ++t;
+         assert (isspace (*t));
+         while (isspace (*t))
+           ++t;
+         if (*t == '\0')
+           break;
+         assert (*t == '"');
+         ++t;
+       }
+    }
+
+  *s = '\0';
+
+  return ret;
+}
diff --git a/binutils/rcparse.y b/binutils/rcparse.y
new file mode 100644 (file)
index 0000000..56c6db8
--- /dev/null
@@ -0,0 +1,1513 @@
+%{ /* rcparse.y -- parser for Windows rc files
+   Copyright 1997 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support.
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* This is a parser for Windows rc files.  It is based on the parser
+   by Gunther Ebert <gunther.ebert@ixos-leipzig.de>.  */
+
+#include "bfd.h"
+#include "bucomm.h"
+#include "libiberty.h"
+#include "windres.h"
+
+/* The current language.  The default is U.S. English.  */
+
+static unsigned short language = 0x409;
+
+/* The resource information during a sub statement.  */
+
+static struct res_res_info sub_res_info;
+
+/* Dialog information.  This is built by the nonterminals styles and
+   controls.  */
+
+static struct dialog dialog;
+
+/* This is used when building a style.  It is modified by the
+   nonterminal styleexpr.  */
+
+static unsigned long style;
+
+/* These are used when building a control.  They are set before using
+   control_params.  */
+
+static unsigned long base_style;
+static unsigned long default_style;
+static unsigned long class;
+
+%}
+
+%union
+{
+  struct accelerator acc;
+  struct accelerator *pacc;
+  struct dialog_control *dialog_control;
+  struct menuitem *menuitem;
+  struct rcdata_data *rcdata;
+  struct stringtable_data *stringtable;
+  struct fixed_versioninfo *fixver;
+  struct ver_info *verinfo;
+  struct ver_stringinfo *verstring;
+  struct ver_varinfo *vervar;
+  struct res_id id;
+  struct res_res_info res_info;
+  struct
+  {
+    unsigned short on;
+    unsigned short off;
+  } memflags;
+  struct
+  {
+    unsigned long val;
+    /* Nonzero if this number was explicitly specified as long.  */
+    int dword;
+  } i;
+  unsigned long il;
+  unsigned short is;
+  char *s;
+};
+
+%token BEG END
+%token ACCELERATORS VIRTKEY ASCII NOINVERT SHIFT CONTROL ALT
+%token BITMAP
+%token CURSOR
+%token DIALOG DIALOGEX EXSTYLE CAPTION CLASS STYLE
+%token AUTO3STATE AUTOCHECKBOX AUTORADIOBUTTON CHECKBOX COMBOBOX CTEXT
+%token DEFPUSHBUTTON EDITTEXT GROUPBOX LISTBOX LTEXT PUSHBOX PUSHBUTTON
+%token RADIOBUTTON RTEXT SCROLLBAR STATE3 USERBUTTON
+%token BEDIT HEDIT IEDIT
+%token FONT
+%token ICON
+%token LANGUAGE CHARACTERISTICS VERSION
+%token MENU MENUEX MENUITEM SEPARATOR POPUP CHECKED GRAYED HELP INACTIVE
+%token MENUBARBREAK MENUBREAK
+%token MESSAGETABLE
+%token RCDATA
+%token STRINGTABLE
+%token VERSIONINFO FILEVERSION PRODUCTVERSION FILEFLAGSMASK FILEFLAGS
+%token FILEOS FILETYPE FILESUBTYPE BLOCKSTRINGFILEINFO BLOCKVARFILEINFO
+%token VALUE
+%token <s> BLOCK
+%token MOVEABLE FIXED PURE IMPURE PRELOAD LOADONCALL DISCARDABLE
+%token NOT
+%token <s> QUOTEDSTRING STRING
+%token <i> NUMBER
+
+%type <pacc> acc_entries
+%type <acc> acc_entry acc_event
+%type <dialog_control> control control_params
+%type <menuitem> menuitems menuitem menuexitems menuexitem
+%type <rcdata> optrcdata_data rcdata_data opt_control_data
+%type <fixver> fixedverinfo
+%type <verinfo> verblocks
+%type <verstring> vervals
+%type <vervar> vertrans
+%type <res_info> suboptions memflags_move_discard memflags_move
+%type <memflags> memflag
+%type <id> id
+%type <il> exstyle parennumber
+%type <il> numexpr posnumexpr cnumexpr optcnumexpr cposnumexpr
+%type <is> acc_options acc_option menuitem_flags menuitem_flag
+%type <s> optstringc file_name
+%type <i> sizednumexpr sizedposnumexpr
+
+%left '|'
+%left '^'
+%left '&'
+%left '+' '-'
+%left '*' '/' '%'
+%right '~' NEG
+
+%%
+
+input:
+         /* empty */
+       | input accelerator
+       | input bitmap
+       | input cursor
+       | input dialog
+       | input font
+       | input icon
+       | input language
+       | input menu
+       | input menuex
+       | input messagetable
+       | input rcdata
+       | input stringtable
+       | input user
+       | input versioninfo
+       ;
+
+/* Accelerator resources.  */
+
+accelerator:
+         id ACCELERATORS suboptions BEG acc_entries END
+         {
+           define_accelerator ($1, &$3, $5);
+         }
+       ;
+
+acc_entries:
+         /* empty */
+         {
+           $$ = NULL;
+         }
+       | acc_entries acc_entry
+         {
+           struct accelerator *a;
+
+           a = (struct accelerator *) xmalloc (sizeof *a);
+           *a = $2;
+           if ($1 == NULL)
+             $$ = a;
+           else
+             {
+               struct accelerator **pp;
+
+               for (pp = &$1->next; *pp != NULL; pp = &(*pp)->next)
+                 ;
+               *pp = a;
+               $$ = $1;
+             }
+         }
+       ;
+
+acc_entry:
+         acc_event cposnumexpr
+         {
+           $$ = $1;
+           $$.id = $2;
+         }
+       | acc_event cposnumexpr ',' acc_options
+         {
+           $$ = $1;
+           $$.id = $2;
+           $$.flags |= $4;
+         }
+       ;
+
+acc_event:
+         QUOTEDSTRING
+         {
+           char *s = $1;
+
+           $$.id = 0;
+           if (*s != '^')
+             $$.flags = 0;
+           else
+             {
+               $$.flags = ACC_CONTROL;
+               ++s;
+             }
+           $$.key = *s;
+           if (s[1] != '\0')
+             rcparse_warning ("accelerator should only be one character");
+           free (s);
+         }
+       | posnumexpr
+         {
+           $$.flags = 0;
+           $$.id = 0;
+           $$.key = $1;
+         }
+       ;
+
+acc_options:
+         acc_option
+         {
+           $$ = $1;
+         }
+       | acc_options ',' acc_option
+         {
+           $$ = $1 | $3;
+         }
+       ;
+
+acc_option:
+         VIRTKEY
+         {
+           $$ = ACC_VIRTKEY;
+         }
+       | ASCII
+         {
+           /* This is just the absence of VIRTKEY.  */
+           $$ = 0;
+         }
+       | NOINVERT
+         {
+           $$ = ACC_NOINVERT;
+         }
+       | SHIFT
+         {
+           $$ = ACC_SHIFT;
+         }
+       | CONTROL
+         {
+           $$ = ACC_CONTROL;
+         }
+       | ALT
+         {
+           $$ = ACC_ALT;
+         }
+       ;
+
+/* Bitmap resources.  */
+
+bitmap:
+         id BITMAP memflags_move file_name
+         {
+           define_bitmap ($1, &$3, $4);
+           free ($4);
+         }
+       ;
+
+/* Cursor resources.  */
+
+cursor:
+         id CURSOR memflags_move_discard file_name
+         {
+           define_cursor ($1, &$3, $4);
+           free ($4);
+         }
+       ;
+
+/* Dialog resources.  */
+
+dialog:
+         id DIALOG memflags_move exstyle posnumexpr cnumexpr cnumexpr
+           cnumexpr
+           {
+             memset (&dialog, 0, sizeof dialog);
+             dialog.x = $5;
+             dialog.y = $6;
+             dialog.width = $7;
+             dialog.height = $8;
+             dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU;
+             dialog.exstyle = $4;
+             dialog.font = NULL;
+             dialog.ex = NULL;
+             dialog.controls = NULL;
+             sub_res_info = $3;
+           }
+           styles BEG controls END
+         {
+           define_dialog ($1, &sub_res_info, &dialog);
+         }
+       | id DIALOGEX memflags_move exstyle posnumexpr cnumexpr cnumexpr
+           cnumexpr
+           {
+             memset (&dialog, 0, sizeof dialog);
+             dialog.x = $5;
+             dialog.y = $6;
+             dialog.width = $7;
+             dialog.height = $8;
+             dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU;
+             dialog.exstyle = $4;
+             dialog.font = NULL;
+             dialog.ex = ((struct dialog_ex *)
+                          xmalloc (sizeof (struct dialog_ex)));
+             memset (dialog.ex, 0, sizeof (struct dialog_ex));
+             dialog.controls = NULL;
+             sub_res_info = $3;
+           }
+           styles BEG controls END
+         {
+           define_dialog ($1, &sub_res_info, &dialog);
+         }
+       | id DIALOGEX memflags_move exstyle posnumexpr cnumexpr cnumexpr
+           cnumexpr cnumexpr
+           {
+             memset (&dialog, 0, sizeof dialog);
+             dialog.x = $5;
+             dialog.y = $6;
+             dialog.width = $7;
+             dialog.height = $8;
+             dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU;
+             dialog.exstyle = $4;
+             dialog.font = NULL;
+             dialog.ex = ((struct dialog_ex *)
+                          xmalloc (sizeof (struct dialog_ex)));
+             memset (dialog.ex, 0, sizeof (struct dialog_ex));
+             dialog.ex->help = $9;
+             dialog.controls = NULL;
+             sub_res_info = $3;
+           }
+           styles BEG controls END
+         {
+           define_dialog ($1, &sub_res_info, &dialog);
+         }
+       ;
+
+exstyle:
+         /* empty */
+         {
+           $$ = 0;
+         }
+       | EXSTYLE '=' numexpr
+         {
+           $$ = $3;
+         }
+       ;
+
+styles:
+         /* empty */
+       | styles CAPTION QUOTEDSTRING
+         {
+           dialog.caption = $3;
+         }
+       | styles CLASS id
+         {
+           dialog.class = $3;
+         }
+       | styles STYLE
+           { style = dialog.style }
+           styleexpr
+         {
+           dialog.style = style;
+         }
+       | styles EXSTYLE numexpr
+         {
+           dialog.exstyle = $3;
+         }
+       | styles FONT numexpr ',' QUOTEDSTRING
+         {
+           dialog.pointsize = $3;
+           dialog.font = $5;
+         }
+       | styles FONT numexpr ',' QUOTEDSTRING cnumexpr cnumexpr
+         {
+           dialog.pointsize = $3;
+           dialog.font = $5;
+           if (dialog.ex == NULL)
+             rcparse_warning ("extended FONT requires DIALOGEX");
+           else
+             {
+               dialog.ex->weight = $6;
+               dialog.ex->italic = $7;
+             }
+         }
+       | styles MENU id
+         {
+           dialog.menu = $3;
+         }
+       | styles CHARACTERISTICS numexpr
+         {
+           sub_res_info.characteristics = $3;
+         }
+       | styles LANGUAGE numexpr cnumexpr
+         {
+           sub_res_info.language = $3 | ($4 << 8);
+         }
+       | styles VERSION numexpr
+         {
+           sub_res_info.version = $3;
+         }
+       ;
+
+controls:
+         /* empty */
+       | controls control
+         {
+           struct dialog_control **pp;
+
+           for (pp = &dialog.controls; *pp != NULL; pp = &(*pp)->next)
+             ;
+           *pp = $2;
+         }
+       ;
+
+control:
+         AUTO3STATE
+           {
+             default_style = BS_AUTO3STATE | WS_TABSTOP;
+             base_style = BS_AUTO3STATE;
+             class = CTL_BUTTON;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | AUTOCHECKBOX
+           {
+             default_style = BS_AUTOCHECKBOX | WS_TABSTOP;
+             base_style = BS_AUTOCHECKBOX;
+             class = CTL_BUTTON;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | AUTORADIOBUTTON
+           {
+             default_style = BS_AUTORADIOBUTTON | WS_TABSTOP;
+             base_style = BS_AUTORADIOBUTTON;
+             class = CTL_BUTTON;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | BEDIT
+           {
+             default_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
+             base_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
+             class = CTL_EDIT;
+           }
+           control_params
+         {
+           $$ = $3;
+           if (dialog.ex == NULL)
+             rcparse_warning ("IEDIT requires DIALOGEX");
+           res_string_to_id (&$$->class, "BEDIT");
+         }
+       | CHECKBOX
+           {
+             default_style = BS_CHECKBOX | WS_TABSTOP;
+             base_style = BS_CHECKBOX | WS_TABSTOP;
+             class = CTL_BUTTON;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | COMBOBOX
+           {
+             default_style = CBS_SIMPLE | WS_TABSTOP;
+             base_style = 0;
+             class = CTL_COMBOBOX;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | CONTROL optstringc numexpr cnumexpr control_styleexpr cnumexpr
+           cnumexpr cnumexpr cnumexpr optcnumexpr opt_control_data
+         {
+           $$ = define_control ($2, $3, $6, $7, $8, $9, $4, style, $10);
+           if ($11 != NULL)
+             {
+               if (dialog.ex == NULL)
+                 rcparse_warning ("control data requires DIALOGEX");
+               $$->data = $11;
+             }
+         }
+       | CONTROL optstringc numexpr cnumexpr control_styleexpr cnumexpr
+           cnumexpr cnumexpr cnumexpr cnumexpr cnumexpr opt_control_data
+         {
+           $$ = define_control ($2, $3, $6, $7, $8, $9, $4, style, $10);
+           if (dialog.ex == NULL)
+             rcparse_warning ("help ID requires DIALOGEX");
+           $$->help = $11;
+           $$->data = $12;
+         }
+       | CTEXT
+           {
+             default_style = SS_CENTER | WS_GROUP;
+             base_style = SS_CENTER;
+             class = CTL_STATIC;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | DEFPUSHBUTTON
+           {
+             default_style = BS_DEFPUSHBUTTON | WS_TABSTOP;
+             base_style = BS_DEFPUSHBUTTON | WS_TABSTOP;
+             class = CTL_BUTTON;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | EDITTEXT
+           {
+             default_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
+             base_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
+             class = CTL_EDIT;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | GROUPBOX
+           {
+             default_style = BS_GROUPBOX;
+             base_style = BS_GROUPBOX;
+             class = CTL_BUTTON;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | HEDIT
+           {
+             default_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
+             base_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
+             class = CTL_EDIT;
+           }
+           control_params
+         {
+           $$ = $3;
+           if (dialog.ex == NULL)
+             rcparse_warning ("IEDIT requires DIALOGEX");
+           res_string_to_id (&$$->class, "HEDIT");
+         }
+       | ICON optstringc numexpr cnumexpr cnumexpr opt_control_data
+         {
+           $$ = define_control ($2, $3, $4, $5, 0, 0, CTL_STATIC,
+                                SS_ICON | WS_CHILD | WS_VISIBLE, 0);
+           if ($6 != NULL)
+             {
+               if (dialog.ex == NULL)
+                 rcparse_warning ("control data requires DIALOGEX");
+               $$->data = $6;
+             }
+         }
+       | ICON optstringc numexpr cnumexpr cnumexpr cnumexpr cnumexpr
+           icon_styleexpr optcnumexpr opt_control_data
+         {
+           $$ = define_control ($2, $3, $4, $5, $6, $7, CTL_STATIC,
+                                style, $9);
+           if ($10 != NULL)
+             {
+               if (dialog.ex == NULL)
+                 rcparse_warning ("control data requires DIALOGEX");
+               $$->data = $10;
+             }
+         }
+       | ICON optstringc numexpr cnumexpr cnumexpr cnumexpr cnumexpr
+           icon_styleexpr cnumexpr cnumexpr opt_control_data
+         {
+           $$ = define_control ($2, $3, $4, $5, $6, $7, CTL_STATIC,
+                                style, $9);
+           if (dialog.ex == NULL)
+             rcparse_warning ("help ID requires DIALOGEX");
+           $$->help = $10;
+           $$->data = $11;
+         }
+       | IEDIT
+           {
+             default_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
+             base_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
+             class = CTL_EDIT;
+           }
+           control_params
+         {
+           $$ = $3;
+           if (dialog.ex == NULL)
+             rcparse_warning ("IEDIT requires DIALOGEX");
+           res_string_to_id (&$$->class, "IEDIT");
+         }
+       | LISTBOX
+           {
+             default_style = LBS_NOTIFY | WS_BORDER;
+             base_style = LBS_NOTIFY | WS_BORDER;
+             class = CTL_LISTBOX;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | LTEXT
+           {
+             default_style = SS_LEFT | WS_GROUP;
+             base_style = SS_LEFT;
+             class = CTL_STATIC;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | PUSHBOX
+           {
+             default_style = BS_PUSHBOX | WS_TABSTOP;
+             base_style = BS_PUSHBOX;
+             class = CTL_BUTTON;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | PUSHBUTTON
+           {
+             default_style = BS_PUSHBUTTON | WS_TABSTOP;
+             base_style = BS_PUSHBUTTON | WS_TABSTOP;
+             class = CTL_BUTTON;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | RADIOBUTTON
+           {
+             default_style = BS_RADIOBUTTON | WS_TABSTOP;
+             base_style = BS_RADIOBUTTON;
+             class = CTL_BUTTON;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | RTEXT
+           {
+             default_style = SS_RIGHT | WS_GROUP;
+             base_style = SS_RIGHT;
+             class = CTL_STATIC;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | SCROLLBAR
+           {
+             default_style = SBS_HORZ;
+             base_style = 0;
+             class = CTL_SCROLLBAR;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | STATE3
+           {
+             default_style = BS_3STATE | WS_TABSTOP;
+             base_style = BS_3STATE;
+             class = CTL_BUTTON;
+           }
+           control_params
+         {
+           $$ = $3;
+         }
+       | USERBUTTON QUOTEDSTRING ',' numexpr ',' numexpr ',' numexpr ','
+           numexpr ',' numexpr ',' 
+           { style = WS_CHILD | WS_VISIBLE }
+           styleexpr optcnumexpr
+         {
+           $$ = define_control ($2, $4, $6, $8, $10, $12, CTL_BUTTON,
+                                style, $16);
+         }
+       ;
+
+/* Parameters for a control.  The static variables DEFAULT_STYLE,
+   BASE_STYLE, and CLASS must be initialized before this nonterminal
+   is used.  DEFAULT_STYLE is the style to use if no style expression
+   is specified.  BASE_STYLE is the base style to use if a style
+   expression is specified; the style expression modifies the base
+   style.  CLASS is the class of the control.  */
+
+control_params:
+         optstringc numexpr cnumexpr cnumexpr cnumexpr cnumexpr
+           opt_control_data
+         {
+           $$ = define_control ($1, $2, $3, $4, $5, $6, class,
+                                default_style | WS_CHILD | WS_VISIBLE, 0);
+           if ($7 != NULL)
+             {
+               if (dialog.ex == NULL)
+                 rcparse_warning ("control data requires DIALOGEX");
+               $$->data = $7;
+             }
+         }
+       | optstringc numexpr cnumexpr cnumexpr cnumexpr cnumexpr
+           control_params_styleexpr optcnumexpr opt_control_data
+         {
+           $$ = define_control ($1, $2, $3, $4, $5, $6, class, style, $8);
+           if ($9 != NULL)
+             {
+               if (dialog.ex == NULL)
+                 rcparse_warning ("control data requires DIALOGEX");
+               $$->data = $9;
+             }
+         }
+       | optstringc numexpr cnumexpr cnumexpr cnumexpr cnumexpr
+           control_params_styleexpr cnumexpr cnumexpr opt_control_data
+         {
+           $$ = define_control ($1, $2, $3, $4, $5, $6, class, style, $8);
+           if (dialog.ex == NULL)
+             rcparse_warning ("help ID requires DIALOGEX");
+           $$->help = $9;
+           $$->data = $10;
+         }
+       ;
+
+optstringc:
+         /* empty */
+         {
+           $$ = NULL;
+         }
+       | QUOTEDSTRING ','
+         {
+           $$ = $1;
+         }
+       ;
+
+opt_control_data:
+         /* empty */
+         {
+           $$ = NULL;
+         }
+       | BEG optrcdata_data END
+         {
+           $$ = $2;
+         }
+       ;
+
+/* These only exist to parse a reduction out of a common case.  */
+
+control_styleexpr:
+         ','
+         { style = WS_CHILD | WS_VISIBLE; }
+         styleexpr
+       ;
+
+icon_styleexpr:
+         ','
+         { style = SS_ICON | WS_CHILD | WS_VISIBLE; }
+         styleexpr
+       ;
+
+control_params_styleexpr:
+         ','
+         { style = base_style | WS_CHILD | WS_VISIBLE; }
+         styleexpr
+       ;
+
+/* Font resources.  */
+
+font:
+         id FONT memflags_move_discard file_name
+         {
+           define_font ($1, &$3, $4);
+           free ($4);
+         }
+       ;
+
+/* Icon resources.  */
+
+icon:
+         id ICON memflags_move_discard file_name
+         {
+           define_icon ($1, &$3, $4);
+           free ($4);
+         }
+       ;
+
+/* Language command.  This changes the static variable language, which
+   affects all subsequent resources.  */
+
+language:
+         LANGUAGE numexpr cnumexpr
+         {
+           language = $2 | ($3 << 8);
+         }
+       ;
+
+/* Menu resources.  */
+
+menu:
+         id MENU suboptions BEG menuitems END
+         {
+           define_menu ($1, &$3, $5);
+         }
+       ;
+
+menuitems:
+         /* empty */
+         {
+           $$ = NULL;
+         }
+       | menuitems menuitem
+         {
+           if ($1 == NULL)
+             $$ = $2;
+           else
+             {
+               struct menuitem **pp;
+
+               for (pp = &$1->next; *pp != NULL; pp = &(*pp)->next)
+                 ;
+               *pp = $2;
+               $$ = $1;
+             }
+         }
+       ;
+
+menuitem:
+         MENUITEM QUOTEDSTRING cnumexpr menuitem_flags
+         {
+           $$ = define_menuitem ($2, $3, $4, 0, 0, NULL);
+         }
+       | MENUITEM SEPARATOR
+         {
+           $$ = define_menuitem (NULL, 0, 0, 0, 0, NULL);
+         }
+       | POPUP QUOTEDSTRING menuitem_flags BEG menuitems END
+         {
+           $$ = define_menuitem ($2, 0, $3, 0, 0, $5);
+         }
+       ;
+
+menuitem_flags:
+         /* empty */
+         {
+           $$ = 0;
+         }
+       | menuitem_flags ',' menuitem_flag
+         {
+           $$ = $1 | $3;
+         }
+       | menuitem_flags menuitem_flag
+         {
+           $$ = $1 | $2;
+         }
+       ;
+
+menuitem_flag:
+         CHECKED
+         {
+           $$ = MENUITEM_CHECKED;
+         }
+       | GRAYED
+         {
+           $$ = MENUITEM_GRAYED;
+         }
+       | HELP
+         {
+           $$ = MENUITEM_HELP;
+         }
+       | INACTIVE
+         {
+           $$ = MENUITEM_INACTIVE;
+         }
+       | MENUBARBREAK
+         {
+           $$ = MENUITEM_MENUBARBREAK;
+         }
+       | MENUBREAK
+         {
+           $$ = MENUITEM_MENUBREAK;
+         }
+       ;
+
+/* Menuex resources.  */
+
+menuex:
+         id MENUEX suboptions BEG menuexitems END
+         {
+           define_menu ($1, &$3, $5);
+         }
+       ;
+
+menuexitems:
+         /* empty */
+         {
+           $$ = NULL;
+         }
+       | menuexitems menuexitem
+         {
+           if ($1 == NULL)
+             $$ = $2;
+           else
+             {
+               struct menuitem **pp;
+
+               for (pp = &$1->next; *pp != NULL; pp = &(*pp)->next)
+                 ;
+               *pp = $2;
+               $$ = $1;
+             }
+         }
+       ;
+
+menuexitem:
+         MENUITEM QUOTEDSTRING
+         {
+           $$ = define_menuitem ($2, 0, 0, 0, 0, NULL);
+         }
+       | MENUITEM QUOTEDSTRING cnumexpr
+         {
+           $$ = define_menuitem ($2, $3, 0, 0, 0, NULL);
+         }
+       | MENUITEM QUOTEDSTRING cnumexpr cnumexpr optcnumexpr
+         {
+           $$ = define_menuitem ($2, $3, $4, $5, 0, NULL);
+         }
+       | POPUP QUOTEDSTRING BEG menuexitems END
+         {
+           $$ = define_menuitem ($2, 0, 0, 0, 0, $4);
+         }
+       | POPUP QUOTEDSTRING cnumexpr BEG menuexitems END
+         {
+           $$ = define_menuitem ($2, $3, 0, 0, 0, $5);
+         }
+       | POPUP QUOTEDSTRING cnumexpr cnumexpr BEG menuexitems END
+         {
+           $$ = define_menuitem ($2, $3, $4, 0, 0, $6);
+         }
+       | POPUP QUOTEDSTRING cnumexpr cnumexpr cnumexpr optcnumexpr
+           BEG menuexitems END
+         {
+           $$ = define_menuitem ($2, $3, $4, $5, $6, $8);
+         }
+       ;
+
+/* Messagetable resources.  */
+
+messagetable:
+         id MESSAGETABLE memflags_move file_name
+         {
+           define_messagetable ($1, &$3, $4);
+           free ($4);
+         }
+       ;
+
+/* Rcdata resources.  */
+
+rcdata:
+         id RCDATA suboptions BEG optrcdata_data END
+         {
+           define_rcdata ($1, &$3, $5);
+         }
+       ;
+
+optrcdata_data:
+         /* empty */
+         {
+           $$ = NULL;
+         }
+       | rcdata_data
+         {
+           $$ = $1;
+         }
+       ;
+
+rcdata_data:
+         QUOTEDSTRING
+         {
+           $$ = append_rcdata_string (NULL, $1);
+         }
+       | sizednumexpr
+         {
+           $$ = append_rcdata_number (NULL, $1.val, $1.dword);
+         }
+       | rcdata_data ',' QUOTEDSTRING
+         {
+           $$ = append_rcdata_string ($1, $3);
+         }
+       | rcdata_data ',' sizednumexpr
+         {
+           $$ = append_rcdata_number ($1, $3.val, $3.dword);
+         }
+       ;
+
+/* Stringtable resources.  */
+
+stringtable:
+         STRINGTABLE suboptions BEG 
+           { sub_res_info = $2; }
+           string_data END
+       ;
+
+string_data:
+         /* empty */
+       | string_data numexpr QUOTEDSTRING
+         {
+           define_stringtable (&sub_res_info, $2, $3);
+         }
+       | string_data numexpr ',' QUOTEDSTRING
+         {
+           define_stringtable (&sub_res_info, $2, $4);
+         }
+       ;
+
+/* User defined resources.  We accept general suboptions in the
+   file_name case to keep the parser happy.  */
+
+user:
+         id id suboptions BEG rcdata_data END
+         {
+           define_user_data ($1, $2, &$3, $5);
+         }
+       | id id suboptions file_name
+         {
+           define_user_file ($1, $2, &$3, $4);
+           free ($4);
+         }
+       ;
+
+/* Versioninfo resources.  */
+
+versioninfo:
+         id VERSIONINFO fixedverinfo BEG verblocks END
+         {
+           define_versioninfo ($1, language, $3, $5);
+         }
+       ;
+
+fixedverinfo:
+         /* empty */
+         {
+           $$ = ((struct fixed_versioninfo *)
+                 xmalloc (sizeof (struct fixed_versioninfo)));
+           memset ($$, 0, sizeof (struct fixed_versioninfo));
+         }
+       | fixedverinfo FILEVERSION numexpr cnumexpr cnumexpr cnumexpr
+         {
+           $1->file_version_ms = ($3 << 16) | $4;
+           $1->file_version_ls = ($5 << 16) | $6;
+           $$ = $1;
+         }
+       | fixedverinfo PRODUCTVERSION numexpr cnumexpr cnumexpr cnumexpr
+         {
+           $1->product_version_ms = ($3 << 16) | $4;
+           $1->product_version_ls = ($5 << 16) | $6;
+           $$ = $1;
+         }
+       | fixedverinfo FILEFLAGSMASK numexpr
+         {
+           $1->file_flags_mask = $3;
+           $$ = $1;
+         }
+       | fixedverinfo FILEFLAGS numexpr
+         {
+           $1->file_flags = $3;
+           $$ = $1;
+         }
+       | fixedverinfo FILEOS numexpr
+         {
+           $1->file_os = $3;
+           $$ = $1;
+         }
+       | fixedverinfo FILETYPE numexpr
+         {
+           $1->file_type = $3;
+           $$ = $1;
+         }
+       | fixedverinfo FILESUBTYPE numexpr
+         {
+           $1->file_subtype = $3;
+           $$ = $1;
+         }
+       ;
+
+/* To handle verblocks successfully, the lexer handles BLOCK
+   specially.  A BLOCK "StringFileInfo" is returned as
+   BLOCKSTRINGFILEINFO.  A BLOCK "VarFileInfo" is returned as
+   BLOCKVARFILEINFO.  A BLOCK with some other string returns BLOCK
+   with the string as the value.  */
+
+verblocks:
+         /* empty */
+         {
+           $$ = NULL;
+         }
+       | verblocks BLOCKSTRINGFILEINFO BEG BLOCK BEG vervals END END
+         {
+           $$ = append_ver_stringfileinfo ($1, $4, $6);
+         }
+       | verblocks BLOCKVARFILEINFO BEG VALUE QUOTEDSTRING vertrans END
+         {
+           $$ = append_ver_varfileinfo ($1, $5, $6);
+         }
+       ;
+
+vervals:
+         /* empty */
+         {
+           $$ = NULL;
+         }
+       | vervals VALUE QUOTEDSTRING ',' QUOTEDSTRING
+         {
+           $$ = append_verval ($1, $3, $5);
+         }
+       ;
+
+vertrans:
+         /* empty */
+         {
+           $$ = NULL;
+         }
+       | vertrans cnumexpr cnumexpr
+         {
+           $$ = append_vertrans ($1, $2, $3);
+         }
+       ;
+
+/* A resource ID.  */
+
+id:
+         posnumexpr
+         {
+           $$.named = 0;
+           $$.u.id = $1;
+         }
+       | STRING
+         {
+           res_string_to_id (&$$, $1);
+           free ($1);
+         }
+       ;
+
+/* Generic suboptions.  These may appear before the BEGIN in any
+   multiline statement.  */
+
+suboptions:
+         /* empty */
+         {
+           memset (&$$, 0, sizeof (struct res_res_info));
+           $$.language = language;
+           /* FIXME: Is this the right default?  */
+           $$.memflags = MEMFLAG_MOVEABLE;
+         }
+       | suboptions memflag
+         {
+           $$ = $1;
+           $$.memflags |= $2.on;
+           $$.memflags &=~ $2.off;
+         }
+       | suboptions CHARACTERISTICS numexpr
+         {
+           $$ = $1;
+           $$.characteristics = $3;
+         }
+       | suboptions LANGUAGE numexpr cnumexpr
+         {
+           $$ = $1;
+           $$.language = $3 | ($4 << 8);
+         }
+       | suboptions VERSION numexpr
+         {
+           $$ = $1;
+           $$.version = $3;
+         }
+       ;
+
+/* Memory flags which default to MOVEABLE and DISCARDABLE.  */
+
+memflags_move_discard:
+         /* empty */
+         {
+           memset (&$$, 0, sizeof (struct res_res_info));
+           $$.language = language;
+           $$.memflags = MEMFLAG_MOVEABLE | MEMFLAG_DISCARDABLE;
+         }
+       | memflags_move_discard memflag
+         {
+           $$ = $1;
+           $$.memflags |= $2.on;
+           $$.memflags &=~ $2.off;
+         }
+       ;
+
+/* Memory flags which default to MOVEABLE.  */
+
+memflags_move:
+         /* empty */
+         {
+           memset (&$$, 0, sizeof (struct res_res_info));
+           $$.language = language;
+           $$.memflags = MEMFLAG_MOVEABLE;
+         }
+       | memflags_move_discard memflag
+         {
+           $$ = $1;
+           $$.memflags |= $2.on;
+           $$.memflags &=~ $2.off;
+         }
+       ;
+
+/* Memory flags.  This returns a struct with two integers, because we
+   sometimes want to set bits and we sometimes want to clear them.  */
+
+memflag:
+         MOVEABLE
+         {
+           $$.on = MEMFLAG_MOVEABLE;
+           $$.off = 0;
+         }
+       | FIXED
+         {
+           $$.on = 0;
+           $$.off = MEMFLAG_MOVEABLE;
+         }
+       | PURE
+         {
+           $$.on = MEMFLAG_PURE;
+           $$.off = 0;
+         }
+       | IMPURE
+         {
+           $$.on = 0;
+           $$.off = MEMFLAG_PURE;
+         }
+       | PRELOAD
+         {
+           $$.on = MEMFLAG_PRELOAD;
+           $$.off = 0;
+         }
+       | LOADONCALL
+         {
+           $$.on = 0;
+           $$.off = MEMFLAG_PRELOAD;
+         }
+       | DISCARDABLE
+         {
+           $$.on = MEMFLAG_DISCARDABLE;
+           $$.off = 0;
+         }
+       ;
+
+/* A file name.  */
+
+file_name:
+         QUOTEDSTRING
+         {
+           $$ = $1;
+         }
+       | STRING
+         {
+           $$ = $1;
+         }
+       ;
+
+/* A style expression.  This changes the static variable STYLE.  We do
+   it this way because rc appears to permit a style to be set to
+   something like
+       WS_GROUP | NOT WS_TABSTOP
+   to mean that a default of WS_TABSTOP should be removed.  Anything
+   which wants to accept a style must first set STYLE to the default
+   value.  The styleexpr nonterminal will change STYLE as specified by
+   the user.  Note that we do not accept arbitrary expressions here,
+   just numbers separated by '|'.  */
+
+styleexpr:
+         parennumber
+         {
+           style |= $1;
+         }
+       | NOT parennumber
+         {
+           style &=~ $2;
+         }
+       | styleexpr '|' parennumber
+         {
+           style |= $3;
+         }
+       | styleexpr '|' NOT parennumber
+         {
+           style &=~ $4;
+         }
+       ;
+
+parennumber:
+         NUMBER
+         {
+           $$ = $1.val;
+         }
+       | '(' numexpr ')'
+         {
+           $$ = $2;
+         }
+       ;
+
+/* An optional expression with a leading comma.  */
+
+optcnumexpr:
+         /* empty */
+         {
+           $$ = 0;
+         }
+       | cnumexpr
+         {
+           $$ = $1;
+         }
+       ;
+
+/* An expression with a leading comma.  */
+
+cnumexpr:
+         ',' numexpr
+         {
+           $$ = $2;
+         }
+       ;
+
+/* A possibly negated numeric expression.  */
+
+numexpr:
+         sizednumexpr
+         {
+           $$ = $1.val;
+         }
+       ;
+
+/* A possibly negated expression with a size.  */
+
+sizednumexpr:
+         NUMBER
+         {
+           $$ = $1;
+         }
+       | '(' sizednumexpr ')'
+         {
+           $$ = $2;
+         }
+       | '~' sizednumexpr %prec '~'
+         {
+           $$.val = ~ $2.val;
+           $$.dword = $2.dword;
+         }
+       | '-' sizednumexpr %prec NEG
+         {
+           $$.val = - $2.val;
+           $$.dword = $2.dword;
+         }
+       | sizednumexpr '*' sizednumexpr
+         {
+           $$.val = $1.val * $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizednumexpr '/' sizednumexpr
+         {
+           $$.val = $1.val / $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizednumexpr '%' sizednumexpr
+         {
+           $$.val = $1.val % $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizednumexpr '+' sizednumexpr
+         {
+           $$.val = $1.val + $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizednumexpr '-' sizednumexpr
+         {
+           $$.val = $1.val - $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizednumexpr '&' sizednumexpr
+         {
+           $$.val = $1.val & $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizednumexpr '^' sizednumexpr
+         {
+           $$.val = $1.val ^ $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizednumexpr '|' sizednumexpr
+         {
+           $$.val = $1.val | $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       ;
+
+/* An expression with a leading comma which does not use unary
+   negation.  */
+
+cposnumexpr:
+         ',' posnumexpr
+         {
+           $$ = $2;
+         }
+       ;
+
+/* An expression which does not use unary negation.  */
+
+posnumexpr:
+         sizedposnumexpr
+         {
+           $$ = $1.val;
+         }
+       ;
+
+/* An expression which does not use unary negation.  We separate unary
+   negation to avoid parsing conflicts when two numeric expressions
+   appear consecutively.  */
+
+sizedposnumexpr:
+         NUMBER
+         {
+           $$ = $1;
+         }
+       | '(' sizednumexpr ')'
+         {
+           $$ = $2;
+         }
+       | '~' sizednumexpr %prec '~'
+         {
+           $$.val = ~ $2.val;
+           $$.dword = $2.dword;
+         }
+       | sizedposnumexpr '*' sizednumexpr
+         {
+           $$.val = $1.val * $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizedposnumexpr '/' sizednumexpr
+         {
+           $$.val = $1.val / $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizedposnumexpr '%' sizednumexpr
+         {
+           $$.val = $1.val % $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizedposnumexpr '+' sizednumexpr
+         {
+           $$.val = $1.val + $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizedposnumexpr '-' sizednumexpr
+         {
+           $$.val = $1.val - $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizedposnumexpr '&' sizednumexpr
+         {
+           $$.val = $1.val & $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizedposnumexpr '^' sizednumexpr
+         {
+           $$.val = $1.val ^ $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       | sizedposnumexpr '|' sizednumexpr
+         {
+           $$.val = $1.val | $3.val;
+           $$.dword = $1.dword || $3.dword;
+         }
+       ;
+
+%%
+
+/* Set the language from the command line.  */
+
+void
+rcparse_set_language (lang)
+     int lang;
+{
+  language = lang;
+}
diff --git a/binutils/resrc.c b/binutils/resrc.c
new file mode 100644 (file)
index 0000000..64c6c78
--- /dev/null
@@ -0,0 +1,2220 @@
+/* resrc.c -- read and write Windows rc files.
+   Copyright 1997 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support.
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* This file contains function that read and write Windows rc files.
+   These are text files that represent resources.  */
+
+#include "bfd.h"
+#include "bucomm.h"
+#include "libiberty.h"
+#include "windres.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+/* The default preprocessor.  */
+
+#define DEFAULT_PREPROCESSOR "gcc -E -xc-header -DRC_INVOKED"
+
+/* We read the directory entries in a cursor or icon file into
+   instances of this structure.  */
+
+struct icondir
+{
+  /* Width of image.  */
+  unsigned char width;
+  /* Height of image.  */
+  unsigned char height;
+  /* Number of colors in image.  */
+  unsigned char colorcount;
+  union
+  {
+    struct
+    {
+      /* Color planes.  */
+      unsigned short planes;
+      /* Bits per pixel.  */
+      unsigned short bits;
+    } icon;
+    struct
+    {
+      /* X coordinate of hotspot.  */
+      unsigned short xhotspot;
+      /* Y coordinate of hotspot.  */
+      unsigned short yhotspot;
+    } cursor;
+  } u;
+  /* Bytes in image.  */
+  unsigned long bytes;
+  /* File offset of image.  */
+  unsigned long offset;
+};
+
+/* The name of the rc file we are reading.  */
+
+char *rc_filename;
+
+/* The line number in the rc file.  */
+
+int rc_lineno;
+
+/* The pipe we are reading from, so that we can close it if we exit.  */
+
+static FILE *cpp_pipe;
+
+/* As we read the rc file, we attach information to this structure.  */
+
+static struct res_directory *resources;
+
+/* The number of cursor resources we have written out.  */
+
+static int cursors;
+
+/* The number of font resources we have written out.  */
+
+static int fonts;
+
+/* Font directory information.  */
+
+struct fontdir *fontdirs;
+
+/* Resource info to use for fontdirs.  */
+
+struct res_res_info fontdirs_resinfo;
+
+/* The number of icon resources we have written out.  */
+
+static int icons;
+
+/* Local functions.  */
+
+static void close_pipe PARAMS ((void));
+static void unexpected_eof PARAMS ((const char *));
+static int get_word PARAMS ((FILE *, const char *));
+static unsigned long get_long PARAMS ((FILE *, const char *));
+static void get_data
+  PARAMS ((FILE *, unsigned char *, unsigned long, const char *));
+static void define_fontdirs PARAMS ((void));
+\f
+/* Read an rc file.  */
+
+struct res_directory *
+read_rc_file (filename, preprocessor, preprocargs, language)
+     const char *filename;
+     const char *preprocessor;
+     const char *preprocargs;
+     int language;
+{
+  char *cmd;
+
+  if (preprocessor == NULL)
+    preprocessor = DEFAULT_PREPROCESSOR;
+
+  if (preprocargs == NULL)
+    preprocargs = "";
+  if (filename == NULL)
+    filename = "-";
+
+  cmd = xmalloc (strlen (preprocessor)
+                + strlen (preprocargs)
+                + strlen (filename)
+                + 10);
+  sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
+
+  cpp_pipe = popen (cmd, FOPEN_RT);
+  if (cpp_pipe == NULL)
+    fatal ("can't popen `%s': %s", cmd, strerror (errno));
+
+  xatexit (close_pipe);
+
+  rc_filename = xstrdup (filename);
+  rc_lineno = 1;
+  if (language != -1)
+    rcparse_set_language (language);
+  yyin = cpp_pipe;
+  yyparse ();
+
+  if (pclose (cpp_pipe) != 0)
+    fprintf (stderr, "%s: warning: preprocessor failed\n", program_name);
+  cpp_pipe = NULL;
+
+  if (fontdirs != NULL)
+    define_fontdirs ();
+
+  free (rc_filename);
+  rc_filename = NULL;
+
+  return resources;
+}
+
+/* Close the pipe if it is open.  This is called via xatexit.  */
+
+void
+close_pipe ()
+{
+  if (cpp_pipe != NULL)
+    pclose (cpp_pipe);
+}
+
+/* Report an error while reading an rc file.  */
+
+void
+yyerror (msg)
+     const char *msg;
+{
+  fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
+}
+
+/* Issue a warning while reading an rc file.  */
+
+void
+rcparse_warning (msg)
+     const char *msg;
+{
+  fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
+}
+
+/* Die if we get an unexpected end of file.  */
+
+static void
+unexpected_eof (msg)
+     const char *msg;
+{
+  fatal ("%s: unexpected EOF", msg);
+}
+
+/* Read a 16 bit word from a file.  The data is assumed to be little
+   endian.  */
+
+static int
+get_word (e, msg)
+     FILE *e;
+     const char *msg;
+{
+  int b1, b2;
+
+  b1 = getc (e);
+  b2 = getc (e);
+  if (feof (e))
+    unexpected_eof (msg);
+  return ((b2 & 0xff) << 8) | (b1 & 0xff);
+}
+
+/* Read a 32 bit word from a file.  The data is assumed to be little
+   endian.  */
+
+static unsigned long
+get_long (e, msg)
+     FILE *e;
+     const char *msg;
+{
+  int b1, b2, b3, b4;
+
+  b1 = getc (e);
+  b2 = getc (e);
+  b3 = getc (e);
+  b4 = getc (e);
+  if (feof (e))
+    unexpected_eof (msg);
+  return (((((((b4 & 0xff) << 8)
+             | (b3 & 0xff)) << 8)
+           | (b2 & 0xff)) << 8)
+         | (b1 & 0xff));
+}
+
+/* Read data from a file.  This is a wrapper to do error checking.  */
+
+static void
+get_data (e, p, c, msg)
+     FILE *e;
+     unsigned char *p;
+     unsigned long c;
+     const char *msg;
+{
+  unsigned long got;
+
+  got = fread (p, 1, c, e);
+  if (got == c)
+    return;
+
+  fatal ("%s: read of %lu returned %lu", msg, c, got);
+}
+\f
+/* Define an accelerator resource.  */
+
+void
+define_accelerator (id, resinfo, data)
+     struct res_id id;
+     const struct res_res_info *resinfo;
+     struct accelerator *data;
+{
+  struct res_resource *r;
+
+  r = define_standard_resource (&resources, RT_ACCELERATORS, id,
+                               resinfo->language, 0);
+  r->type = RES_TYPE_ACCELERATOR;
+  r->u.acc = data;
+  r->res_info = *resinfo;
+}
+
+/* Define a bitmap resource.  Bitmap data is stored in a file.  The
+   first 14 bytes of the file are a standard header, which is not
+   included in the resource data.  */
+
+#define BITMAP_SKIP (14)
+
+void
+define_bitmap (id, resinfo, filename)
+     struct res_id id;
+     const struct res_res_info *resinfo;
+     const char *filename;
+{
+  FILE *e;
+  char *real_filename;
+  struct stat s;
+  unsigned char *data;
+  int i;
+  struct res_resource *r;
+
+  e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
+
+  if (stat (real_filename, &s) < 0)
+    fatal ("stat failed on bitmap file `%s': %s", real_filename,
+          strerror (errno));
+
+  data = (unsigned char *) xmalloc (s.st_size - BITMAP_SKIP);
+
+  for (i = 0; i < BITMAP_SKIP; i++)
+    getc (e);
+
+  get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
+
+  fclose (e);
+  free (real_filename);
+
+  r = define_standard_resource (&resources, RT_BITMAP, id,
+                               resinfo->language, 0);
+
+  r->type = RES_TYPE_BITMAP;
+  r->u.data.length = s.st_size - BITMAP_SKIP;
+  r->u.data.data = data;
+  r->res_info = *resinfo;
+}
+
+/* Define a cursor resource.  A cursor file may contain a set of
+   bitmaps, each representing the same cursor at various different
+   resolutions.  They each get written out with a different ID.  The
+   real cursor resource is then a group resource which can be used to
+   select one of the actual cursors.  */
+
+void
+define_cursor (id, resinfo, filename)
+     struct res_id id;
+     const struct res_res_info *resinfo;
+     const char *filename;
+{
+  FILE *e;
+  char *real_filename;
+  int type, count, i;
+  struct icondir *icondirs;
+  int first_cursor;
+  struct res_resource *r;
+  struct group_cursor *first, **pp;
+
+  e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
+
+  /* A cursor file is basically an icon file.  The start of the file
+     is a three word structure.  The first word is ignored.  The
+     second word is the type of data.  The third word is the number of
+     entries.  */
+
+  get_word (e, real_filename);
+  type = get_word (e, real_filename);
+  count = get_word (e, real_filename);
+  if (type != 2)
+    fatal ("cursor file `%s' does not contain cursor data", real_filename);
+
+  /* Read in the icon directory entries.  */
+
+  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
+
+  for (i = 0; i < count; i++)
+    {
+      icondirs[i].width = getc (e);
+      icondirs[i].height = getc (e);
+      icondirs[i].colorcount = getc (e);
+      getc (e);
+      icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
+      icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
+      icondirs[i].bytes = get_long (e, real_filename);
+      icondirs[i].offset = get_long (e, real_filename);
+
+      if (feof (e))
+       unexpected_eof (real_filename);
+    }
+
+  /* Define each cursor as a unique resource.  */
+
+  first_cursor = cursors;
+
+  for (i = 0; i < count; i++)
+    {
+      unsigned char *data;
+      struct res_id name;
+      struct cursor *c;
+
+      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
+       fatal ("%s: fseek to %lu failed: %s", real_filename,
+              icondirs[i].offset, strerror (errno));
+
+      data = (unsigned char *) xmalloc (icondirs[i].bytes);
+
+      get_data (e, data, icondirs[i].bytes, real_filename);
+
+      c = (struct cursor *) xmalloc (sizeof *c);
+      c->xhotspot = icondirs[i].u.cursor.xhotspot;
+      c->yhotspot = icondirs[i].u.cursor.yhotspot;
+      c->length = icondirs[i].bytes;
+      c->data = data;
+
+      ++cursors;
+
+      name.named = 0;
+      name.u.id = cursors;
+
+      r = define_standard_resource (&resources, RT_CURSOR, name,
+                                   resinfo->language, 0);
+      r->type = RES_TYPE_CURSOR;
+      r->u.cursor = c;
+      r->res_info = *resinfo;
+    }
+
+  fclose (e);
+  free (real_filename);
+
+  /* Define a cursor group resource.  */
+
+  first = NULL;
+  pp = &first;
+  for (i = 0; i < count; i++)
+    {
+      struct group_cursor *cg;
+
+      /* These manipulations of icondirs into cg are copied from rcl.  */
+
+      cg = (struct group_cursor *) xmalloc (sizeof *cg);
+      cg->next = NULL;
+      cg->width = icondirs[i].width;
+      cg->height = 2 * icondirs[i].height;
+      cg->planes = 1;
+      cg->bits = 4;
+      cg->bytes = icondirs[i].bytes + 8;
+      cg->index = first_cursor + i + 1;
+
+      *pp = cg;
+      pp = &(*pp)->next;
+    }
+
+  r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
+                               resinfo->language, 0);
+  r->type = RES_TYPE_GROUP_CURSOR;
+  r->u.group_cursor = first;
+  r->res_info = *resinfo;
+}
+
+/* Define a dialog resource.  */
+
+void
+define_dialog (id, resinfo, dialog)
+     struct res_id id;
+     const struct res_res_info *resinfo;
+     const struct dialog *dialog;
+{
+  struct dialog *copy;
+  struct res_resource *r;
+
+  copy = (struct dialog *) xmalloc (sizeof *copy);
+  *copy = *dialog;
+
+  r = define_standard_resource (&resources, RT_DIALOG, id,
+                               resinfo->language, 0);
+  r->type = RES_TYPE_DIALOG;
+  r->u.dialog = copy;
+  r->res_info = *resinfo;
+}
+
+/* Define a dialog control.  This does not define a resource, but
+   merely allocates and fills in a structure.  */
+
+struct dialog_control *
+define_control (text, id, x, y, width, height, class, style, exstyle)
+     char *text;
+     unsigned long id;
+     unsigned long x;
+     unsigned long y;
+     unsigned long width;
+     unsigned long height;
+     unsigned long class;
+     unsigned long style;
+     unsigned long exstyle;
+{
+  struct dialog_control *n;
+
+  n = (struct dialog_control *) xmalloc (sizeof *n);
+  n->next = NULL;
+  n->id = id;
+  n->style = style;
+  n->exstyle = exstyle;
+  n->x = x;
+  n->y = y;
+  n->width = width;
+  n->height = height;
+  n->class.named = 0;
+  n->class.u.id = class;
+  if (text != NULL)
+    res_string_to_id (&n->text, text);
+  else
+    {
+      n->text.named = 0;
+      n->text.u.id = 0;
+    }
+  free (text);
+  n->data = NULL;
+  n->help = 0;
+
+  return n;
+}
+
+/* Define a font resource.  */
+
+void
+define_font (id, resinfo, filename)
+     struct res_id id;
+     const struct res_res_info *resinfo;
+     const char *filename;
+{
+  FILE *e;
+  char *real_filename;
+  struct stat s;
+  unsigned char *data;
+  struct res_resource *r;
+  struct fontdir *fd;
+  long offset;
+  const char *device, *face;
+  struct fontdir **pp;
+
+  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
+
+  if (stat (real_filename, &s) < 0)
+    fatal ("stat failed on bitmap file `%s': %s", real_filename,
+          strerror (errno));
+
+  data = (unsigned char *) xmalloc (s.st_size);
+
+  get_data (e, data, s.st_size, real_filename);
+
+  fclose (e);
+  free (real_filename);
+
+  r = define_standard_resource (&resources, RT_FONT, id,
+                               resinfo->language, 0);
+
+  r->type = RES_TYPE_FONT;
+  r->u.data.length = s.st_size;
+  r->u.data.data = data;
+  r->res_info = *resinfo;
+
+  /* For each font resource, we must add an entry in the FONTDIR
+     resource.  The FONTDIR resource includes some strings in the font
+     file.  To find them, we have to do some magic on the data we have
+     read.  */
+
+  offset = ((((((data[47] << 8)
+               | data[46]) << 8)
+             | data[45]) << 8)
+           | data[44]);
+  if (offset > 0 && offset < s.st_size)
+    device = (char *) data + offset;
+  else
+    device = "";
+
+  offset = ((((((data[51] << 8)
+               | data[50]) << 8)
+             | data[49]) << 8)
+           | data[48]);
+  if (offset > 0 && offset < s.st_size)
+    face = (char *) data + offset;
+  else
+    face = "";
+
+  ++fonts;
+
+  fd = (struct fontdir *) xmalloc (sizeof *fd);
+  fd->next = NULL;
+  fd->index = fonts;
+  fd->length = 58 + strlen (device) + strlen (face);
+  fd->data = (unsigned char *) xmalloc (fd->length);
+
+  memcpy (fd->data, data, 56);
+  strcpy ((char *) fd->data + 56, device);
+  strcpy ((char *) fd->data + 57 + strlen (device), face);
+
+  for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
+    ;
+  *pp = fd;
+
+  /* For the single fontdirs resource, we always use the resource
+     information of the last font.  I don't know what else to do.  */
+  fontdirs_resinfo = *resinfo;
+}
+
+/* Define the fontdirs resource.  This is called after the entire rc
+   file has been parsed, if any font resources were seen.  */
+
+static void
+define_fontdirs ()
+{
+  struct res_resource *r;
+  struct res_id id;
+
+  id.named = 0;
+  id.u.id = 1;
+
+  r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
+
+  r->type = RES_TYPE_FONTDIR;
+  r->u.fontdir = fontdirs;
+  r->res_info = fontdirs_resinfo;
+}
+
+/* Define an icon resource.  An icon file may contain a set of
+   bitmaps, each representing the same icon at various different
+   resolutions.  They each get written out with a different ID.  The
+   real icon resource is then a group resource which can be used to
+   select one of the actual icon bitmaps.  */
+
+void
+define_icon (id, resinfo, filename)
+     struct res_id id;
+     const struct res_res_info *resinfo;
+     const char *filename;
+{
+  FILE *e;
+  char *real_filename;
+  int type, count, i;
+  struct icondir *icondirs;
+  int first_icon;
+  struct res_resource *r;
+  struct group_icon *first, **pp;
+
+  e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
+
+  /* The start of an icon file is a three word structure.  The first
+     word is ignored.  The second word is the type of data.  The third
+     word is the number of entries.  */
+
+  get_word (e, real_filename);
+  type = get_word (e, real_filename);
+  count = get_word (e, real_filename);
+  if (type != 1)
+    fatal ("icon file `%s' does not contain icon data", real_filename);
+
+  /* Read in the icon directory entries.  */
+
+  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
+
+  for (i = 0; i < count; i++)
+    {
+      icondirs[i].width = getc (e);
+      icondirs[i].height = getc (e);
+      icondirs[i].colorcount = getc (e);
+      getc (e);
+      icondirs[i].u.icon.planes = get_word (e, real_filename);
+      icondirs[i].u.icon.bits = get_word (e, real_filename);
+      icondirs[i].bytes = get_long (e, real_filename);
+      icondirs[i].offset = get_long (e, real_filename);
+
+      if (feof (e))
+       unexpected_eof (real_filename);
+    }
+
+  /* Define each icon as a unique resource.  */
+
+  first_icon = icons;
+
+  for (i = 0; i < count; i++)
+    {
+      unsigned char *data;
+      struct res_id name;
+
+      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
+       fatal ("%s: fseek to %lu failed: %s", real_filename,
+              icondirs[i].offset, strerror (errno));
+
+      data = (unsigned char *) xmalloc (icondirs[i].bytes);
+
+      get_data (e, data, icondirs[i].bytes, real_filename);
+
+      ++icons;
+
+      name.named = 0;
+      name.u.id = icons;
+
+      r = define_standard_resource (&resources, RT_ICON, name,
+                                   resinfo->language, 0);
+      r->type = RES_TYPE_ICON;
+      r->u.data.length = icondirs[i].bytes;
+      r->u.data.data = data;
+      r->res_info = *resinfo;
+    }
+
+  fclose (e);
+  free (real_filename);
+
+  /* Define an icon group resource.  */
+
+  first = NULL;
+  pp = &first;
+  for (i = 0; i < count; i++)
+    {
+      struct group_icon *cg;
+
+      /* FIXME: rcl sets planes and bits based on colors, rather than
+         just copying the values from the file.  */
+
+      cg = (struct group_icon *) xmalloc (sizeof *cg);
+      cg->next = NULL;
+      cg->width = icondirs[i].width;
+      cg->height = icondirs[i].height;
+      cg->colors = icondirs[i].colorcount;
+      cg->planes = icondirs[i].u.icon.planes;
+      cg->bits = icondirs[i].u.icon.bits;
+      cg->bytes = icondirs[i].bytes;
+      cg->index = first_icon + i + 1;
+
+      *pp = cg;
+      pp = &(*pp)->next;
+    }
+
+  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
+                               resinfo->language, 0);
+  r->type = RES_TYPE_GROUP_ICON;
+  r->u.group_icon = first;
+  r->res_info = *resinfo;
+}
+
+/* Define a menu resource.  */
+
+void
+define_menu (id, resinfo, menuitems)
+     struct res_id id;
+     const struct res_res_info *resinfo;
+     struct menuitem *menuitems;
+{
+  struct res_resource *r;
+
+  r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
+  r->type = RES_TYPE_MENU;
+  r->u.menu = menuitems;
+  r->res_info = *resinfo;
+}
+
+/* Define a menu item.  This does not define a resource, but merely
+   allocates and fills in a structure.  */
+
+struct menuitem *
+define_menuitem (text, menuid, type, state, help, menuitems)
+     char *text;
+     int menuid;
+     unsigned long type;
+     unsigned long state;
+     unsigned long help;
+     struct menuitem *menuitems;
+{
+  struct menuitem *mi;
+
+  mi = (struct menuitem *) xmalloc (sizeof *mi);
+  mi->next = NULL;
+  mi->type = type;
+  mi->state = state;
+  mi->id = menuid;
+  mi->text = text;
+  mi->help = help;
+  mi->popup = menuitems;
+  return mi;
+}
+
+/* Define a messagetable resource.  */
+
+void
+define_messagetable (id, resinfo, filename)
+     struct res_id id;
+     const struct res_res_info *resinfo;
+     const char *filename;
+{
+  FILE *e;
+  char *real_filename;
+  struct stat s;
+  unsigned char *data;
+  struct res_resource *r;
+
+  e = open_file_search (filename, FOPEN_RB, "messagetable file",
+                       &real_filename);
+
+  if (stat (real_filename, &s) < 0)
+    fatal ("stat failed on bitmap file `%s': %s", real_filename,
+          strerror (errno));
+
+  data = (unsigned char *) xmalloc (s.st_size);
+
+  get_data (e, data, s.st_size, real_filename);
+
+  fclose (e);
+  free (real_filename);
+
+  r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
+                               resinfo->language, 0);
+
+  r->type = RES_TYPE_MESSAGETABLE;
+  r->u.data.length = s.st_size;
+  r->u.data.data = data;
+  r->res_info = *resinfo;
+}
+
+/* Define an rcdata resource.  */
+
+void
+define_rcdata (id, resinfo, data)
+     struct res_id id;
+     const struct res_res_info *resinfo;
+     struct rcdata_data *data;
+{
+  struct res_resource *r;
+
+  r = define_standard_resource (&resources, RT_RCDATA, id,
+                               resinfo->language, 0);
+  r->type = RES_TYPE_RCDATA;
+  r->u.rcdata = data;
+  r->res_info = *resinfo;
+}
+
+/* Add an rcdata_item to an rcdata resource.  */
+
+struct rcdata_data *
+append_rcdata_item (data, item)
+     struct rcdata_data *data;
+     struct rcdata_item *item;
+{
+  if (data == NULL)
+    {
+      data = (struct rcdata_data *) xmalloc (sizeof *data);
+      data->first = item;
+      data->last = item;
+    }
+  else
+    {
+      data->last->next = item;
+      data->last = item;
+    }
+
+  return data;
+}
+
+/* Add a string to an rcdata resource.  */
+
+struct rcdata_data *
+append_rcdata_string (data, string)
+     struct rcdata_data *data;
+     char *string;
+{
+  struct rcdata_item *ri;
+
+  ri = (struct rcdata_item *) xmalloc (sizeof *ri);
+  ri->next = NULL;
+  ri->type = RCDATA_STRING;
+  ri->u.string = string;
+
+  return append_rcdata_item (data, ri);
+}
+
+/* Add a number to an rcdata resource.  */
+
+struct rcdata_data *
+append_rcdata_number (data, val, dword)
+     struct rcdata_data *data;
+     unsigned long val;
+     int dword;
+{
+  struct rcdata_item *ri;
+
+  ri = (struct rcdata_item *) xmalloc (sizeof *ri);
+  ri->next = NULL;
+  ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
+  ri->u.word = val;
+
+  return append_rcdata_item (data, ri);
+}
+
+/* Define a stringtable resource.  This is called for each string
+   which appears in a STRINGTABLE statement.  */
+
+void
+define_stringtable (resinfo, stringid, string)
+     const struct res_res_info *resinfo;
+     unsigned long stringid;
+     char *string;
+{
+  struct res_id id;
+  struct res_resource *r;
+
+  id.named = 0;
+  id.u.id = stringid >> 4;
+  r = define_standard_resource (&resources, RT_STRING, id,
+                               resinfo->language, 1);
+
+  if (r->type == RES_TYPE_UNINITIALIZED)
+    {
+      int i;
+
+      r->type = RES_TYPE_STRINGTABLE;
+      r->u.stringtable = ((struct stringtable *)
+                         xmalloc (sizeof (struct stringtable)));
+      for (i = 0; i < 16; i++)
+       {
+         r->u.stringtable->strings[i].length = 0;
+         r->u.stringtable->strings[i].string = NULL;
+       }
+
+      r->res_info = *resinfo;
+    }
+
+  unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
+                     &r->u.stringtable->strings[stringid & 0xf].string,
+                     string);
+  free (string);
+}
+
+/* Define a user data resource where the data is in the rc file.  */
+
+void
+define_user_data (id, type, resinfo, data)
+     struct res_id id;
+     struct res_id type;
+     const struct res_res_info *resinfo;
+     struct rcdata_data *data;
+{
+  struct res_id ids[3];
+  struct res_resource *r;
+
+  ids[0] = type;
+  ids[1] = id;
+  ids[2].named = 0;
+  ids[2].u.id = resinfo->language;
+
+  r = define_resource (&resources, 3, ids, 0);
+  r->type = RES_TYPE_USERDATA;
+  r->u.userdata = data;
+  r->res_info = *resinfo;
+}
+
+/* Define a user data resource where the data is in a file.  */
+
+void
+define_user_file (id, type, resinfo, filename)
+     struct res_id id;
+     struct res_id type;
+     const struct res_res_info *resinfo;
+     const char *filename;
+{
+  FILE *e;
+  char *real_filename;
+  struct stat s;
+  unsigned char *data;
+  struct res_id ids[3];
+  struct res_resource *r;
+
+  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
+
+  if (stat (real_filename, &s) < 0)
+    fatal ("stat failed on bitmap file `%s': %s", real_filename,
+          strerror (errno));
+
+  data = (unsigned char *) xmalloc (s.st_size);
+
+  get_data (e, data, s.st_size, real_filename);
+
+  fclose (e);
+  free (real_filename);
+
+  ids[0] = type;
+  ids[1] = id;
+  ids[2].named = 0;
+  ids[2].u.id = resinfo->language;
+
+  r = define_resource (&resources, 3, ids, 0);
+  r->type = RES_TYPE_USERDATA;
+  r->u.userdata = ((struct rcdata_data *)
+                  xmalloc (sizeof (struct rcdata_data)));
+  r->u.userdata->first = ((struct rcdata_item *)
+                         xmalloc (sizeof (struct rcdata_item)));
+  r->u.userdata->last = r->u.userdata->first;
+  r->u.userdata->first->next = NULL;
+  r->u.userdata->first->type = RCDATA_BUFFER;
+  r->u.userdata->first->u.buffer.length = s.st_size;
+  r->u.userdata->first->u.buffer.data = data;
+  r->res_info = *resinfo;
+}
+
+/* Define a versioninfo resource.  */
+
+void
+define_versioninfo (id, language, fixedverinfo, verinfo)
+     struct res_id id;
+     int language;
+     struct fixed_versioninfo *fixedverinfo;
+     struct ver_info *verinfo;
+{
+  struct res_resource *r;
+
+  r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
+  r->type = RES_TYPE_VERSIONINFO;
+  r->u.versioninfo = ((struct versioninfo *)
+                     xmalloc (sizeof (struct versioninfo)));
+  r->u.versioninfo->fixed = fixedverinfo;
+  r->u.versioninfo->var = verinfo;
+  r->res_info.language = language;
+}
+
+/* Add string version info to a list of version information.  */
+
+struct ver_info *
+append_ver_stringfileinfo (verinfo, language, strings)
+     struct ver_info *verinfo;
+     char *language;
+     struct ver_stringinfo *strings;
+{
+  struct ver_info *vi, **pp;
+
+  vi = (struct ver_info *) xmalloc (sizeof *vi);
+  vi->next = NULL;
+  vi->type = VERINFO_STRING;
+  unicode_from_ascii ((unsigned short *) NULL, &vi->u.string.language,
+                     language);
+  free (language);
+  vi->u.string.strings = strings;
+
+  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
+    ;
+  *pp = vi;
+
+  return verinfo;
+}
+
+/* Add variable version info to a list of version information.  */
+
+struct ver_info *
+append_ver_varfileinfo (verinfo, key, var)
+     struct ver_info *verinfo;
+     char *key;
+     struct ver_varinfo *var;
+{
+  struct ver_info *vi, **pp;
+
+  vi = (struct ver_info *) xmalloc (sizeof *vi);
+  vi->next = NULL;
+  vi->type = VERINFO_VAR;
+  unicode_from_ascii ((unsigned short *) NULL, &vi->u.var.key, key);
+  free (key);
+  vi->u.var.var = var;
+
+  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
+    ;
+  *pp = vi;
+
+  return verinfo;
+}
+
+/* Append version string information to a list.  */
+
+struct ver_stringinfo *
+append_verval (strings, key, value)
+     struct ver_stringinfo *strings;
+     char *key;
+     char *value;
+{
+  struct ver_stringinfo *vs, **pp;
+
+  vs = (struct ver_stringinfo *) xmalloc (sizeof *vs);
+  vs->next = NULL;
+  unicode_from_ascii ((unsigned short *) NULL, &vs->key, key);
+  free (key);
+  unicode_from_ascii ((unsigned short *) NULL, &vs->value, value);
+  free (value);
+
+  for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
+    ;
+  *pp = vs;
+
+  return strings;
+}
+
+/* Append version variable information to a list.  */
+
+struct ver_varinfo *
+append_vertrans (var, language, charset)
+     struct ver_varinfo *var;
+     unsigned long language;
+     unsigned long charset;
+{
+  struct ver_varinfo *vv, **pp;
+
+  vv = (struct ver_varinfo *) xmalloc (sizeof *vv);
+  vv->next = NULL;
+  vv->language = language;
+  vv->charset = charset;
+
+  for (pp = &var; *pp != NULL; pp = &(*pp)->next)
+    ;
+  *pp = vv;
+
+  return var;
+}
+\f
+/* Local functions used to write out an rc file.  */
+
+static void indent PARAMS ((FILE *, int));
+static void write_rc_directory
+  PARAMS ((FILE *, const struct res_directory *, const struct res_id *,
+          const struct res_id *, int *, int));
+static void write_rc_subdir
+  PARAMS ((FILE *, const struct res_entry *, const struct res_id *,
+          const struct res_id *, int *, int));
+static void write_rc_resource
+  PARAMS ((FILE *, const struct res_id *, const struct res_id *,
+          const struct res_resource *, int *));
+static void write_rc_accelerators
+  PARAMS ((FILE *, const struct accelerator *));
+static void write_rc_cursor PARAMS ((FILE *, const struct cursor *));
+static void write_rc_group_cursor
+  PARAMS ((FILE *, const struct group_cursor *));
+static void write_rc_dialog PARAMS ((FILE *, const struct dialog *));
+static void write_rc_dialog_control
+  PARAMS ((FILE *, const struct dialog_control *));
+static void write_rc_fontdir PARAMS ((FILE *, const struct fontdir *));
+static void write_rc_group_icon PARAMS ((FILE *, const struct group_icon *));
+static void write_rc_menu PARAMS ((FILE *, const struct menuitem *, int, int));
+static void write_rc_rcdata PARAMS ((FILE *, const struct rcdata_data *, int));
+static void write_rc_stringtable
+  PARAMS ((FILE *, const struct res_id *, const struct stringtable *));
+static void write_rc_versioninfo PARAMS ((FILE *, const struct versioninfo *));
+static void write_rc_filedata
+  PARAMS ((FILE *, unsigned long, const unsigned char *));
+
+/* Indent a given number of spaces.  */
+
+static void
+indent (e, c)
+     FILE *e;
+     int c;
+{
+  int i;
+
+  for (i = 0; i < c; i++)
+    putc (' ', e);
+}
+
+/* Dump the resources we have read in the format of an rc file.
+
+   Actually, we don't use the format of an rc file, because it's way
+   too much of a pain--for example, we'd have to write icon resources
+   into a file and refer to that file.  We just generate a readable
+   format that kind of looks like an rc file, and is useful for
+   understanding the contents of a resource file.  Someday we may want
+   to generate an rc file which the rc compiler can read; if that day
+   comes, this code will have to be fixed up.  */
+
+void
+write_rc_file (filename, resources)
+     const char *filename;
+     const struct res_directory *resources;
+{
+  FILE *e;
+  int language;
+
+  if (filename == NULL)
+    e = stdout;
+  else
+    {
+      e = fopen (filename, FOPEN_WT);
+      if (e == NULL)
+       fatal ("can't open `%s' for output: %s", filename, strerror (errno));
+    }
+
+  language = -1;
+  write_rc_directory (e, resources, (const struct res_id *) NULL,
+                     (const struct res_id *) NULL, &language, 1);
+}
+
+/* Write out a directory.  E is the file to write to.  RD is the
+   directory.  TYPE is a pointer to the level 1 ID which serves as the
+   resource type.  NAME is a pointer to the level 2 ID which serves as
+   an individual resource name.  LANGUAGE is a pointer to the current
+   language.  LEVEL is the level in the tree.  */
+
+static void
+write_rc_directory (e, rd, type, name, language, level)
+     FILE *e;
+     const struct res_directory *rd;
+     const struct res_id *type;
+     const struct res_id *name;
+     int *language;
+     int level;
+{
+  const struct res_entry *re;
+
+  /* Print out some COFF information that rc files can't represent.  */
+
+  if (rd->time != 0)
+    fprintf (e, "// Time stamp: %lu\n", rd->time);
+  if (rd->characteristics != 0)
+    fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
+  if (rd->major != 0 || rd->minor != 0)
+    fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
+
+  for (re = rd->entries;  re != NULL; re = re->next)
+    {
+      switch (level)
+       {
+       case 1:
+         /* If we're at level 1, the key of this resource is the
+             type.  This normally duplicates the information we have
+             stored with the resource itself, but we need to remember
+             the type if this is a user define resource type.  */
+         type = &re->id;
+         break;
+
+       case 2:
+         /* If we're at level 2, the key of this resource is the name
+            we are going to use in the rc printout. */
+         name = &re->id;
+         break;
+
+       case 3:
+         /* If we're at level 3, then this key represents a language.
+            Use it to update the current language.  */
+         if (! re->id.named
+             && re->id.u.id != *language
+             && (re->id.u.id & 0xffff) == re->id.u.id)
+           {
+             fprintf (e, "LANGUAGE %lu, %lu\n",
+                      re->id.u.id & 0xff, (re->id.u.id >> 8) & 0xff);
+             *language = re->id.u.id;
+           }
+         break;
+
+       default:
+         break;
+       }
+
+      if (re->subdir)
+       write_rc_subdir (e, re, type, name, language, level);
+      else
+       {
+         if (level == 3)
+           {
+             /* This is the normal case: the three levels are
+                 TYPE/NAME/LANGUAGE.  NAME will have been set at level
+                 2, and represents the name to use.  We probably just
+                 set LANGUAGE, and it will probably match what the
+                 resource itself records if anything.  */
+             write_rc_resource (e, type, name, re->u.res, language);
+           }
+         else
+           {
+             fprintf (e, "// Resource at unexpected level %d\n", level);
+             write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
+                                language);
+           }
+       }
+    }
+}
+
+/* Write out a subdirectory entry.  E is the file to write to.  RE is
+   the subdirectory entry.  TYPE and NAME are pointers to higher level
+   IDs, or NULL.  LANGUAGE is a pointer to the current language.
+   LEVEL is the level in the tree.  */
+
+static void
+write_rc_subdir (e, re, type, name, language, level)
+     FILE *e;
+     const struct res_entry *re;
+     const struct res_id *type;
+     const struct res_id *name;
+     int *language;
+     int level;
+{
+  fprintf (e, "\n");
+  switch (level)
+    {
+    case 1:
+      fprintf (e, "// Type: ");
+      if (re->id.named)
+       res_id_print (e, re->id, 1);
+      else
+       {
+         const char *s;
+
+         switch (re->id.u.id)
+           {
+           case RT_CURSOR: s = "cursor"; break;
+           case RT_BITMAP: s = "bitmap"; break;
+           case RT_ICON: s = "icon"; break;
+           case RT_MENU: s = "menu"; break;
+           case RT_DIALOG: s = "dialog"; break;
+           case RT_STRING: s = "stringtable"; break;
+           case RT_FONTDIR: s = "fontdir"; break;
+           case RT_FONT: s = "font"; break;
+           case RT_ACCELERATORS: s = "accelerators"; break;
+           case RT_RCDATA: s = "rcdata"; break;
+           case RT_MESSAGETABLE: s = "messagetable"; break;
+           case RT_GROUP_CURSOR: s = "group cursor"; break;
+           case RT_GROUP_ICON: s = "group icon"; break;
+           case RT_VERSION: s = "version"; break;
+           case RT_DLGINCLUDE: s = "dlginclude"; break;
+           case RT_PLUGPLAY: s = "plugplay"; break;
+           case RT_VXD: s = "vxd"; break;
+           case RT_ANICURSOR: s = "anicursor"; break;
+           case RT_ANIICON: s = "aniicon"; break;
+           default: s = NULL; break;
+           }
+
+         if (s != NULL)
+           fprintf (e, "%s", s);
+         else
+           res_id_print (e, re->id, 1);
+       }
+      fprintf (e, "\n");
+      break;
+
+    case 2:
+      fprintf (e, "// Name: ");
+      res_id_print (e, re->id, 1);
+      fprintf (e, "\n");
+      break;
+
+    case 3:
+      fprintf (e, "// Language: ");
+      res_id_print (e, re->id, 1);
+      fprintf (e, "\n");
+      break;
+
+    default:
+      fprintf (e, "// Level %d: ", level);
+      res_id_print (e, re->id, 1);
+      fprintf (e, "\n");
+    }          
+
+  write_rc_directory (e, re->u.dir, type, name, language, level + 1);
+}
+
+/* Write out a single resource.  E is the file to write to.  TYPE is a
+   pointer to the type of the resource.  NAME is a pointer to the name
+   of the resource; it will be NULL if there is a level mismatch.  RES
+   is the resource data.  LANGUAGE is a pointer to the current
+   language.  */
+
+static void
+write_rc_resource (e, type, name, res, language)
+     FILE *e;
+     const struct res_id *type;
+     const struct res_id *name;
+     const struct res_resource *res;
+     int *language;
+{
+  const char *s;
+  int rt;
+  int menuex = 0;
+
+  fprintf (e, "\n");
+
+  switch (res->type)
+    {
+    default:
+      abort ();
+
+    case RES_TYPE_ACCELERATOR:
+      s = "ACCELERATOR";
+      rt = RT_ACCELERATORS;
+      break;
+
+    case RES_TYPE_BITMAP:
+      s = "BITMAP";
+      rt = RT_BITMAP;
+      break;
+
+    case RES_TYPE_CURSOR:
+      s = "CURSOR";
+      rt = RT_CURSOR;
+      break;
+
+    case RES_TYPE_GROUP_CURSOR:
+      s = "GROUP_CURSOR";
+      rt = RT_GROUP_CURSOR;
+      break;
+
+    case RES_TYPE_DIALOG:
+      if (extended_dialog (res->u.dialog))
+       s = "DIALOGEX";
+      else
+       s = "DIALOG";
+      rt = RT_DIALOG;
+      break;
+
+    case RES_TYPE_FONT:
+      s = "FONT";
+      rt = RT_FONT;
+      break;
+
+    case RES_TYPE_FONTDIR:
+      s = "FONTDIR";
+      rt = RT_FONTDIR;
+      break;
+
+    case RES_TYPE_ICON:
+      s = "ICON";
+      rt = RT_ICON;
+      break;
+
+    case RES_TYPE_GROUP_ICON:
+      s = "GROUP_ICON";
+      rt = RT_GROUP_ICON;
+      break;
+
+    case RES_TYPE_MENU:
+      if (extended_menu (res->u.menu))
+       {
+         s = "MENUEX";
+         menuex = 1;
+       }
+      else
+       {
+         s = "MENU";
+         menuex = 0;
+       }
+      rt = RT_MENU;
+      break;
+
+    case RES_TYPE_MESSAGETABLE:
+      s = "MESSAGETABLE";
+      rt = RT_MESSAGETABLE;
+      break;
+
+    case RES_TYPE_RCDATA:
+      s = "RCDATA";
+      rt = RT_RCDATA;
+      break;
+
+    case RES_TYPE_STRINGTABLE:
+      s = "STRINGTABLE";
+      rt = RT_STRING;
+      break;
+
+    case RES_TYPE_USERDATA:
+      s = NULL;
+      rt = 0;
+      break;
+
+    case RES_TYPE_VERSIONINFO:
+      s = "VERSIONINFO";
+      rt = RT_VERSION;
+      break;
+    }
+
+  if (rt != 0
+      && type != NULL
+      && (type->named || type->u.id != rt))
+    {
+      fprintf (e, "// Unexpected resource type mismatch: ");
+      res_id_print (e, *type, 1);
+      fprintf (e, " != %d", rt);
+    }
+
+  if (res->coff_info.codepage != 0)
+    fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
+  if (res->coff_info.reserved != 0)
+    fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
+
+  if (name != NULL)
+    res_id_print (e, *name, 0);
+  else
+    fprintf (e, "??Unknown-Name??");
+
+  fprintf (e, " ");
+  if (s != NULL)
+    fprintf (e, "%s", s);
+  else if (type != NULL)
+    res_id_print (e, *type, 0);
+  else
+    fprintf (e, "??Unknown-Type??");
+
+  if (res->res_info.memflags != 0)
+    {
+      if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
+       fprintf (e, " MOVEABLE");
+      if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
+       fprintf (e, " PURE");
+      if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
+       fprintf (e, " PRELOAD");
+      if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
+       fprintf (e, " DISCARDABLE");
+    }
+
+  if (res->type == RES_TYPE_DIALOG)
+    {
+      fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
+              res->u.dialog->width, res->u.dialog->height);
+      if (res->u.dialog->ex != NULL
+         && res->u.dialog->ex->help != 0)
+       fprintf (e, ", %lu", res->u.dialog->ex->help);
+    }
+
+  fprintf (e, "\n");
+
+  if ((res->res_info.language != 0 && res->res_info.language != *language)
+      || res->res_info.characteristics != 0
+      || res->res_info.version != 0)
+    {
+      int modifiers;
+
+      switch (res->type)
+       {
+       case RES_TYPE_ACCELERATOR:
+       case RES_TYPE_DIALOG:
+       case RES_TYPE_MENU:
+       case RES_TYPE_RCDATA:
+       case RES_TYPE_STRINGTABLE:
+         modifiers = 1;
+         break;
+
+       default:
+         modifiers = 0;
+         break;
+       }
+
+      if (res->res_info.language != 0 && res->res_info.language != *language)
+       fprintf (e, "%sLANGUAGE %d, %d\n",
+                modifiers ? "// " : "",
+                res->res_info.language & 0xff,
+                (res->res_info.language >> 8) & 0xff);
+      if (res->res_info.characteristics != 0)
+       fprintf (e, "%sCHARACTERISTICS %lu\n",
+                modifiers ? "// " : "",
+                res->res_info.characteristics);
+      if (res->res_info.version != 0)
+       fprintf (e, "%sVERSION %lu\n",
+                modifiers ? "// " : "",
+                res->res_info.version);
+    }
+
+  switch (res->type)
+    {
+    default:
+      abort ();
+
+    case RES_TYPE_ACCELERATOR:
+      write_rc_accelerators (e, res->u.acc);
+      break;
+
+    case RES_TYPE_CURSOR:
+      write_rc_cursor (e, res->u.cursor);
+      break;
+
+    case RES_TYPE_GROUP_CURSOR:
+      write_rc_group_cursor (e, res->u.group_cursor);
+      break;
+
+    case RES_TYPE_DIALOG:
+      write_rc_dialog (e, res->u.dialog);
+      break;
+
+    case RES_TYPE_FONTDIR:
+      write_rc_fontdir (e, res->u.fontdir);
+      break;
+
+    case RES_TYPE_GROUP_ICON:
+      write_rc_group_icon (e, res->u.group_icon);
+      break;
+
+    case RES_TYPE_MENU:
+      write_rc_menu (e, res->u.menu, menuex, 0);
+      break;
+
+    case RES_TYPE_RCDATA:
+      write_rc_rcdata (e, res->u.rcdata, 0);
+      break;
+
+    case RES_TYPE_STRINGTABLE:
+      write_rc_stringtable (e, name, res->u.stringtable);
+      break;
+
+    case RES_TYPE_USERDATA:
+      write_rc_rcdata (e, res->u.userdata, 0);
+      break;
+
+    case RES_TYPE_VERSIONINFO:
+      write_rc_versioninfo (e, res->u.versioninfo);
+      break;
+
+    case RES_TYPE_BITMAP:
+    case RES_TYPE_FONT:
+    case RES_TYPE_ICON:
+    case RES_TYPE_MESSAGETABLE:
+      write_rc_filedata (e, res->u.data.length, res->u.data.data);
+      break;
+    }
+}
+
+/* Write out accelerator information.  */
+
+static void
+write_rc_accelerators (e, accelerators)
+     FILE *e;
+     const struct accelerator *accelerators;
+{
+  const struct accelerator *acc;
+
+  fprintf (e, "BEGIN\n");
+  for (acc = accelerators; acc != NULL; acc = acc->next)
+    {
+      int printable;
+
+      fprintf (e, "  ");
+
+      if ((acc->key & 0x7f) == acc->key
+         && isprint ((unsigned char) acc->key)
+         && (acc->flags & ACC_VIRTKEY) == 0)
+       {
+         fprintf (e, "\"%c\"", acc->key);
+         printable = 1;
+       }
+      else
+       {
+         fprintf (e, "%d", acc->key);
+         printable = 0;
+       }
+
+      fprintf (e, ", %d", acc->id);
+
+      if (! printable)
+       {
+         if ((acc->flags & ACC_VIRTKEY) != 0)
+           fprintf (e, ", VIRTKEY");
+         else
+           fprintf (e, ", ASCII");
+       }
+
+      if ((acc->flags & ACC_SHIFT) != 0)
+       fprintf (e, ", SHIFT");
+      if ((acc->flags & ACC_CONTROL) != 0)
+       fprintf (e, ", CONTROL");
+      if ((acc->flags & ACC_ALT) != 0)
+       fprintf (e, ", ALT");
+
+      fprintf (e, "\n");
+    }
+
+  fprintf (e, "END\n");
+}
+
+/* Write out cursor information.  This would normally be in a separate
+   file, which the rc file would include.  */
+
+static void
+write_rc_cursor (e, cursor)
+     FILE *e;
+     const struct cursor *cursor;
+{
+  fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
+          cursor->yhotspot);
+  write_rc_filedata (e, cursor->length, cursor->data);
+}
+
+/* Write out group cursor data.  This would normally be built from the
+   cursor data.  */
+
+static void
+write_rc_group_cursor (e, group_cursor)
+     FILE *e;
+     const struct group_cursor *group_cursor;
+{
+  const struct group_cursor *gc;
+
+  for (gc = group_cursor; gc != NULL; gc = gc->next)
+    {
+      fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
+            gc->width, gc->height, gc->planes, gc->bits);
+      fprintf (e, "// data bytes: %lu; index: %d\n",
+              gc->bytes, gc->index);
+    }
+}
+
+/* Write dialog data.  */
+
+static void
+write_rc_dialog (e, dialog)
+     FILE *e;
+     const struct dialog *dialog;
+{
+  const struct dialog_control *control;
+
+  if (dialog->style != 0)
+    fprintf (e, "STYLE 0x%lx\n", dialog->style);
+  if (dialog->exstyle != 0)
+    fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
+  if (dialog->class.named || dialog->class.u.id != 0)
+    {
+      fprintf (e, "CLASS ");
+      res_id_print (e, dialog->class, 0);
+      fprintf (e, "\n");
+    }
+  if (dialog->caption != NULL)
+    fprintf (e, "CAPTION \"%s\"\n", dialog->caption);
+  if (dialog->menu.named || dialog->menu.u.id != 0)
+    {
+      fprintf (e, "MENU ");
+      res_id_print (e, dialog->menu, 0);
+      fprintf (e, "\n");
+    }
+  if (dialog->font != NULL)
+    {
+      fprintf (e, "FONT %d, \"%s\"", dialog->pointsize, dialog->font);
+      if (dialog->ex != NULL
+         && (dialog->ex->weight != 0 || dialog->ex->italic != 0))
+       fprintf (e, ", %d, %d", dialog->ex->weight, dialog->ex->italic);
+      fprintf (e, "\n");
+    }
+
+  fprintf (e, "BEGIN\n");
+
+  for (control = dialog->controls; control != NULL; control = control->next)
+    write_rc_dialog_control (e, control);
+
+  fprintf (e, "END\n");
+}
+
+/* For each predefined control keyword, this table provides the class
+   and the style.  */
+
+struct control_info
+{
+  const char *name;
+  unsigned short class;
+  unsigned long style;
+};
+
+static const struct control_info control_info[] =
+{
+  { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
+  { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
+  { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
+  { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
+  { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
+  { "CTEXT", CTL_STATIC, SS_CENTER },
+  { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
+  { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
+  { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
+  { "ICON", CTL_STATIC, SS_ICON },
+  { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
+  { "LTEXT", CTL_STATIC, SS_LEFT },
+  { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
+  { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
+  { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
+  { "RTEXT", CTL_STATIC, SS_RIGHT },
+  { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
+  { "STATE3", CTL_BUTTON, BS_3STATE },
+  /* It's important that USERBUTTON come after all the other button
+     types, so that it won't be matched too early.  */
+  { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
+  { NULL, 0, 0 }
+};
+
+/* Write a dialog control.  */
+
+static void
+write_rc_dialog_control (e, control)
+     FILE *e;
+     const struct dialog_control *control;
+{
+  const struct control_info *ci;
+
+  fprintf (e, "  ");
+
+  if (control->class.named)
+    ci = NULL;
+  else
+    {
+      for (ci = control_info; ci->name != NULL; ++ci)
+       if (ci->class == control->class.u.id
+           && (ci->style == (unsigned long) -1
+               || ci->style == (control->style & 0xff)))
+         break;
+    }
+
+  if (ci->name != NULL)
+    fprintf (e, "%s", ci->name);
+  else
+    fprintf (e, "CONTROL");
+  
+  if (control->text.named || control->text.u.id != 0)
+    {
+      fprintf (e, " ");
+      res_id_print (e, control->text, 1);
+      fprintf (e, ",");
+    }
+
+  fprintf (e, " %d, ", control->id);
+
+  if (ci->name == NULL)
+    {
+      res_id_print (e, control->class, 0);
+      fprintf (e, ", 0x%lx, ", control->style);
+    }
+
+  fprintf (e, "%d, %d", control->x, control->y);
+
+  if (control->style != SS_ICON
+      || control->exstyle != 0
+      || control->width != 0
+      || control->height != 0
+      || control->help != 0)
+    {
+      fprintf (e, ", %d, %d", control->width, control->height);
+
+      /* FIXME: We don't need to print the style if it is the default.
+        More importantly, in certain cases we actually need to turn
+        off parts of the forced style, by using NOT.  */
+      fprintf (e, ", 0x%lx", control->style);
+
+      if (control->exstyle != 0 || control->help != 0)
+       fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
+    }
+
+  fprintf (e, "\n");
+
+  if (control->data != NULL)
+    write_rc_rcdata (e, control->data, 2);
+}
+
+/* Write out font directory data.  This would normally be built from
+   the font data.  */
+
+static void
+write_rc_fontdir (e, fontdir)
+     FILE *e;
+     const struct fontdir *fontdir;
+{
+  const struct fontdir *fc;
+
+  for (fc = fontdir; fc != NULL; fc = fc->next)
+    {
+      fprintf (e, "// Font index: %d\n", fc->index);
+      write_rc_filedata (e, fc->length, fc->data);
+    }
+}
+
+/* Write out group icon data.  This would normally be built from the
+   icon data.  */
+
+static void
+write_rc_group_icon (e, group_icon)
+     FILE *e;
+     const struct group_icon *group_icon;
+{
+  const struct group_icon *gi;
+
+  for (gi = group_icon; gi != NULL; gi = gi->next)
+    {
+      fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
+              gi->width, gi->height, gi->colors, gi->planes, gi->bits);
+      fprintf (e, "// data bytes: %lu; index: %d\n",
+              gi->bytes, gi->index);
+    }
+}
+
+/* Write out a menu resource.  */
+
+static void
+write_rc_menu (e, menuitems, menuex, ind)
+     FILE *e;
+     const struct menuitem *menuitems;
+     int menuex;
+     int ind;
+{
+  const struct menuitem *mi;
+
+  indent (e, ind);
+  fprintf (e, "BEGIN\n");
+
+  for (mi = menuitems; mi != NULL; mi = mi->next)
+    {
+      indent (e, ind + 2);
+
+      if (mi->popup == NULL)
+       fprintf (e, "MENUITEM");
+      else
+       fprintf (e, "POPUP");
+
+      if (! menuex
+         && mi->popup == NULL
+         && mi->text == NULL
+         && mi->type == 0
+         && mi->id == 0)
+       {
+         fprintf (e, " SEPARATOR\n");
+         continue;
+       }
+
+      if (mi->text == NULL)
+       fprintf (e, " \"\"");
+      else
+       fprintf (e, " \"%s\"", mi->text);
+
+      if (! menuex)
+       {
+         if (mi->popup == NULL)
+           fprintf (e, ", %d", mi->id);
+
+         if ((mi->type & MENUITEM_CHECKED) != 0)
+           fprintf (e, ", CHECKED");
+         if ((mi->type & MENUITEM_GRAYED) != 0)
+           fprintf (e, ", GRAYED");
+         if ((mi->type & MENUITEM_HELP) != 0)
+           fprintf (e, ", HELP");
+         if ((mi->type & MENUITEM_INACTIVE) != 0)
+           fprintf (e, ", INACTIVE");
+         if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
+           fprintf (e, ", MENUBARBREAK");
+         if ((mi->type & MENUITEM_MENUBREAK) != 0)
+           fprintf (e, ", MENUBREAK");
+       }
+      else
+       {
+         if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
+           {
+             fprintf (e, ", %d", mi->id);
+             if (mi->type != 0 || mi->state != 0 || mi->help != 0)
+               {
+                 fprintf (e, ", %lu", mi->type);
+                 if (mi->state != 0 || mi->help != 0)
+                   {
+                     fprintf (e, ", %lu", mi->state);
+                     if (mi->help != 0)
+                       fprintf (e, ", %lu", mi->help);
+                   }
+               }
+           }
+       }
+
+      fprintf (e, "\n");
+
+      if (mi->popup != NULL)
+       write_rc_menu (e, mi->popup, menuex, ind + 2);
+    }
+
+  indent (e, ind);
+  fprintf (e, "END\n");
+}
+
+/* Write out an rcdata resource.  This is also used for other types of
+   resources that need to print arbitrary data.  */
+
+static void
+write_rc_rcdata (e, rcdata, ind)
+     FILE *e;
+     const struct rcdata_data *rcdata;
+     int ind;
+{
+  const struct rcdata_item *ri;
+
+  indent (e, ind);
+  fprintf (e, "BEGIN\n");
+
+  for (ri = rcdata->first; ri != NULL; ri = ri->next)
+    {
+      if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
+       continue;
+
+      indent (e, ind + 2);
+
+      switch (ri->type)
+       {
+       default:
+         abort ();
+
+       case RCDATA_WORD:
+         fprintf (e, "%d", ri->u.word);
+         break;
+
+       case RCDATA_DWORD:
+         fprintf (e, "%luL", ri->u.dword);
+         break;
+
+       case RCDATA_STRING:
+         fprintf (e, "\"%s\"", ri->u.string);
+         break;
+
+       case RCDATA_WSTRING:
+         fprintf (e, "L\"");
+         unicode_print (e, ri->u.wstring, -1);
+         fprintf (e, "\"");
+         break;
+
+       case RCDATA_BUFFER:
+         {
+           unsigned long i;
+           int first;
+
+           /* Assume little endian data.  */
+
+           first = 1;
+           for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
+             {
+               unsigned long l;
+
+               l = ((((((ri->u.buffer.data[i + 3] << 8)
+                        | ri->u.buffer.data[i + 2]) << 8)
+                      | ri->u.buffer.data[i + 1]) << 8)
+                    | ri->u.buffer.data[i]);
+               if (first)
+                 first = 0;
+               else
+                 {
+                   fprintf (e, ",\n");
+                   indent (e, ind);
+                 }
+               fprintf (e, "%luL", l);
+             }
+
+           if (i + 1 < ri->u.buffer.length)
+             {
+               int i;
+
+               i = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
+               if (first)
+                 first = 0;
+               else
+                 {
+                   fprintf (e, ",\n");
+                   indent (e, ind);
+                 }
+               fprintf (e, "%d", i);
+               i += 2;
+             }
+
+           if (i < ri->u.buffer.length)
+             {
+               if (first)
+                 first = 0;
+               else
+                 {
+                   fprintf (e, ",\n");
+                   indent (e, ind);
+                 }
+               if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
+                   && isprint (ri->u.buffer.data[i]))
+                 fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
+               else
+                 fprintf (e, "\"\%03o\"", ri->u.buffer.data[i]);
+             }
+
+           break;
+         }
+       }
+
+      if (ri->next != NULL)
+       fprintf (e, ",");
+      fprintf (e, "\n");
+    }
+
+  indent (e, ind);
+  fprintf (e, "END\n");
+}
+
+/* Write out a stringtable resource.  */
+
+static void
+write_rc_stringtable (e, name, stringtable)
+     FILE *e;
+     const struct res_id *name;
+     const struct stringtable *stringtable;
+{
+  unsigned long offset;
+  int i;
+
+  if (name != NULL && ! name->named)
+    offset = name->u.id << 4;
+  else
+    {
+      fprintf (e, "// %s string table name\n",
+              name == NULL ? "Missing" : "Invalid");
+      offset = 0;
+    }
+
+  fprintf (e, "BEGIN\n");
+
+  for (i = 0; i < 16; i++)
+    {
+      if (stringtable->strings[i].length != 0)
+       {
+         fprintf (e, "  %lu, \"", offset + i);
+         unicode_print (e, stringtable->strings[i].string,
+                        stringtable->strings[i].length);
+         fprintf (e, "\"\n");
+       }
+    }
+
+  fprintf (e, "END\n");
+}
+
+/* Write out a versioninfo resource.  */
+
+static void
+write_rc_versioninfo (e, versioninfo)
+     FILE *e;
+     const struct versioninfo *versioninfo;
+{
+  const struct fixed_versioninfo *f;
+  const struct ver_info *vi;
+
+  f = versioninfo->fixed;
+  if (f->file_version_ms != 0 || f->file_version_ls != 0)
+    fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
+            (f->file_version_ms >> 16) & 0xffff,
+            f->file_version_ms & 0xffff,
+            (f->file_version_ls >> 16) & 0xffff,
+            f->file_version_ls & 0xffff);
+  if (f->product_version_ms != 0 || f->product_version_ls != 0)
+    fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
+            (f->product_version_ms >> 16) & 0xffff,
+            f->product_version_ms & 0xffff,
+            (f->product_version_ls >> 16) & 0xffff,
+            f->product_version_ls & 0xffff);
+  if (f->file_flags_mask != 0)
+    fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
+  if (f->file_flags != 0)
+    fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
+  if (f->file_os != 0)
+    fprintf (e, " FILEOS 0x%lx\n", f->file_os);
+  if (f->file_type != 0)
+    fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
+  if (f->file_subtype != 0)
+    fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
+  if (f->file_date_ms != 0 || f->file_date_ls != 0)
+    fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
+
+  fprintf (e, "BEGIN\n");
+
+  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
+    {
+      switch (vi->type)
+       {
+       case VERINFO_STRING:
+         {
+           const struct ver_stringinfo *vs;
+
+           fprintf (e, "  BLOCK \"StringFileInfo\"\n");
+           fprintf (e, "  BEGIN\n");
+           fprintf (e, "    BLOCK \"");
+           unicode_print (e, vi->u.string.language, -1);
+           fprintf (e, "\"\n");
+           fprintf (e, "    BEGIN\n");
+
+           for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
+             {
+               fprintf (e, "      VALUE \"");
+               unicode_print (e, vs->key, -1);
+               fprintf (e, "\", \"");
+               unicode_print (e, vs->value, -1);
+               fprintf (e, "\"\n");
+             }
+
+           fprintf (e, "    END\n");
+           fprintf (e, "  END\n");
+           break;
+         }
+
+       case VERINFO_VAR:
+         {
+           const struct ver_varinfo *vv;
+
+           fprintf (e, "  BLOCK \"VarFileInfo\"\n");
+           fprintf (e, "  BEGIN\n");
+           fprintf (e, "    VALUE \"");
+           unicode_print (e, vi->u.var.key, -1);
+           fprintf (e, "\"");
+
+           for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
+             fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
+                      vv->charset);
+
+           fprintf (e, "\n  END\n");
+
+           break;
+         }
+       }
+    }
+
+  fprintf (e, "END\n");
+}
+
+/* Write out data which would normally be read from a file.  */
+
+static void
+write_rc_filedata (e, length, data)
+     FILE *e;
+     unsigned long length;
+     const unsigned char *data;
+{
+  unsigned long i;
+
+  for (i = 0; i + 15 < length; i += 16)
+    {
+      fprintf (e, "// %4lx: ", i);
+      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
+              data[i + 0], data[i + 1], data[i + 2], data[i + 3],
+              data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
+      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+              data[i +  8], data[i +  9], data[i + 10], data[i + 11],
+              data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
+    }
+
+  if (i < length)
+    {
+      fprintf (e, "// %4lx:", i);
+      while (i < length)
+       {
+         fprintf (e, " %02x", data[i]);
+         ++i;
+       }
+      fprintf (e, "\n");
+    }
+}
diff --git a/binutils/windres.c b/binutils/windres.c
new file mode 100644 (file)
index 0000000..d08fb97
--- /dev/null
@@ -0,0 +1,912 @@
+/* windres.c -- a program to manipulate Windows resources
+   Copyright 1997 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support.
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* This program can read and write Windows resources in various
+   formats.  In particular, it can act like the rc resource compiler
+   program, and it can act like the cvtres res to COFF conversion
+   program.
+
+   It is based on information taken from the following sources:
+
+   * Microsoft documentation.
+
+   * The rcl program, written by Gunther Ebert
+     <gunther.ebert@ixos-leipzig.de>.
+
+   * The res2coff program, written by Pedro A. Aranda <paag@tid.es>.
+
+   */
+
+#include "bfd.h"
+#include "getopt.h"
+#include "bucomm.h"
+#include "libiberty.h"
+#include "windres.h"
+
+#include <assert.h>
+#include <ctype.h>
+
+/* An enumeration of format types.  */
+
+enum res_format
+{
+  /* Unknown format.  */
+  RES_FORMAT_UNKNOWN,
+  /* Textual RC file.  */
+  RES_FORMAT_RC,
+  /* Binary RES file.  */
+  RES_FORMAT_RES,
+  /* COFF file.  */
+  RES_FORMAT_COFF
+};
+
+/* A structure used to map between format types and strings.  */
+
+struct format_map
+{
+  const char *name;
+  enum res_format format;
+};
+
+/* A mapping between names and format types.  */
+
+static const struct format_map format_names[] =
+{
+  { "rc", RES_FORMAT_RC },
+  { "res", RES_FORMAT_RES },
+  { "coff", RES_FORMAT_COFF },
+  { NULL, RES_FORMAT_UNKNOWN }
+};
+
+/* A mapping from file extensions to format types.  */
+
+static const struct format_map format_fileexts[] =
+{
+  { "rc", RES_FORMAT_RC },
+  { "res", RES_FORMAT_RES },
+  { "exe", RES_FORMAT_COFF },
+  { "obj", RES_FORMAT_COFF },
+  { "o", RES_FORMAT_COFF },
+  { NULL, RES_FORMAT_UNKNOWN }
+};
+
+/* A list of include directories.  */
+
+struct include_dir
+{
+  struct include_dir *next;
+  char *dir;
+};
+
+static struct include_dir *include_dirs;
+
+/* Long options.  */
+
+/* 150 isn't special; it's just an arbitrary non-ASCII char value.  */
+
+#define OPTION_DEFINE 150
+#define OPTION_HELP (OPTION_DEFINE + 1)
+#define OPTION_INCLUDE_DIR (OPTION_HELP + 1)
+#define OPTION_LANGUAGE (OPTION_INCLUDE_DIR + 1)
+#define OPTION_PREPROCESSOR (OPTION_LANGUAGE + 1)
+#define OPTION_VERSION (OPTION_PREPROCESSOR + 1)
+#define OPTION_YYDEBUG (OPTION_VERSION + 1)
+
+static const struct option long_options[] =
+{
+  {"define", required_argument, 0, OPTION_DEFINE},
+  {"help", no_argument, 0, OPTION_HELP},
+  {"include-dir", required_argument, 0, OPTION_INCLUDE_DIR},
+  {"input-format", required_argument, 0, 'I'},
+  {"language", required_argument, 0, OPTION_LANGUAGE},
+  {"output-format", required_argument, 0, 'O'},
+  {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
+  {"target", required_argument, 0, 'F'},
+  {"version", no_argument, 0, OPTION_VERSION},
+  {"yydebug", no_argument, 0, OPTION_YYDEBUG},
+  {0, no_argument, 0, 0}
+};
+
+/* Static functions.  */
+
+static enum res_format format_from_name PARAMS ((const char *));
+static enum res_format format_from_filename PARAMS ((const char *, int));
+static void usage PARAMS ((FILE *, int));
+\f
+/* Open a file using the include directory search list.  */
+
+FILE *
+open_file_search (filename, mode, errmsg, real_filename)
+     const char *filename;
+     const char *mode;
+     const char *errmsg;
+     char **real_filename;
+{
+  FILE *e;
+  struct include_dir *d;
+
+  e = fopen (filename, mode);
+  if (e != NULL)
+    {
+      *real_filename = xstrdup (filename);
+      return e;
+    }
+
+  if (errno == ENOENT)
+    {
+      for (d = include_dirs; d != NULL; d = d->next)
+       {
+         char *n;
+
+         n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
+         sprintf (n, "%s/%s", d->dir, filename);
+         e = fopen (n, mode);
+         if (e != NULL)
+           {
+             *real_filename = n;
+             return e;
+           }
+
+         if (errno != ENOENT)
+           break;
+       }
+    }
+
+  fatal ("can't open %s `%s': %s", errmsg, filename, strerror (errno));
+
+  /* Return a value to avoid a compiler warning.  */
+  return NULL;
+}
+\f
+/* Unicode support.  */
+
+/* Convert an ASCII string to a unicode string.  We just copy it,
+   expanding chars to shorts, rather than doing something intelligent.  */
+
+void
+unicode_from_ascii (length, unicode, ascii)
+     unsigned short *length;
+     unsigned short **unicode;
+     const char *ascii;
+{
+  int len;
+  const char *s;
+  unsigned short *w;
+
+  len = strlen (ascii);
+
+  if (length != NULL)
+    {
+      if (len > 0xffff)
+       fatal ("string too long (%d chars > 0xffff)", len);
+      *length = len;
+    }
+
+  *unicode = (unsigned short *) xmalloc ((len + 1) * sizeof (unsigned short));
+
+  for (s = ascii, w = *unicode; *s != '\0'; s++, w++)
+    *w = *s & 0xff;
+  *w = 0;
+}
+
+/* Print the unicode string UNICODE to the file E.  LENGTH is the
+   number of characters to print, or -1 if we should print until the
+   end of the string.  */
+
+void
+unicode_print (e, unicode, length)
+     FILE *e;
+     const unsigned short *unicode;
+     int length;
+{
+  while (1)
+    {
+      unsigned short ch;
+
+      if (length == 0)
+       return;
+      if (length > 0)
+       --length;
+
+      ch = *unicode;
+
+      if (ch == 0)
+       return;
+
+      ++unicode;
+
+      if ((ch & 0x7f) == ch && isprint (ch))
+       putc (ch, e);
+      else if ((ch & 0xff) == ch)
+       fprintf (e, "\\%03o", (unsigned int) ch);
+      else
+       fprintf (e, "\\x%x", (unsigned int) ch);
+    }
+}
+\f
+/* Compare two resource ID's.  We consider name entries to come before
+   numeric entries, because that is how they appear in the COFF .rsrc
+   section.  */
+
+int
+res_id_cmp (a, b)
+     struct res_id a;
+     struct res_id b;
+{
+  if (! a.named)
+    {
+      if (b.named)
+       return 1;
+      if (a.u.id > b.u.id)
+       return 1;
+      else if (a.u.id < b.u.id)
+       return -1;
+      else
+       return 0;
+    }
+  else
+    {
+      unsigned short *as, *ase, *bs, *bse;
+
+      if (! b.named)
+       return -1;
+
+      as = a.u.n.name;
+      ase = as + a.u.n.length;
+      bs = b.u.n.name;
+      bse = bs + b.u.n.length;
+
+      while (as < ase)
+       {
+         int i;
+
+         if (bs >= bse)
+           return 1;
+         i = (int) *as - (int) *bs;
+         if (i != 0)
+           return i;
+         ++as;
+         ++bs;
+       }
+
+      if (bs < bse)
+       return -1;
+
+      return 0;
+    }
+}
+
+/* Print a resource ID.  */
+
+void
+res_id_print (stream, id, quote)
+     FILE *stream;
+     struct res_id id;
+     int quote;
+{
+  if (! id.named)
+    fprintf (stream, "%lu", id.u.id);
+  else
+    {
+      unsigned short *s, *se;
+
+      if (quote)
+       putc ('"', stream);
+      s = id.u.n.name;
+      se = s + id.u.n.length;
+      while (s < se)
+       {
+         if (*s == '"')
+           fprintf (stream, "\\\"");
+         else if ((*s & 0xff) == *s && isprint (*s))
+           putc (*s, stream);
+         else
+           fprintf (stream, "\\%03o", *s);
+         ++s;
+       }
+      if (quote)
+       putc ('"', stream);
+    }
+}
+
+/* Print a list of resource ID's.  */
+
+void
+res_ids_print (stream, cids, ids)
+     FILE *stream;
+     int cids;
+     const struct res_id *ids;
+{
+  int i;
+
+  for (i = 0; i < cids; i++)
+    {
+      res_id_print (stream, ids[i], 1);
+      if (i + 1 < cids)
+       fprintf (stream, ": ");
+    }
+}
+
+/* Convert an ASCII string to a resource ID.  */
+
+void
+res_string_to_id (res_id, string)
+     struct res_id *res_id;
+     const char *string;
+{
+  res_id->named = 1;
+  unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
+}
+
+/* Define a resource.  The arguments are the resource tree, RESOURCES,
+   and the location at which to put it in the tree, CIDS and IDS.
+   This returns a newly allocated res_resource structure, which the
+   caller is expected to initialize.  If DUPOK is non-zero, then if a
+   resource with this ID exists, it is returned.  Otherwise, a warning
+   is issued, and a new resource is created replacing the existing
+   one.  */
+
+struct res_resource *
+define_resource (resources, cids, ids, dupok)
+     struct res_directory **resources;
+     int cids;
+     const struct res_id *ids;
+     int dupok;
+{
+  struct res_entry *re = NULL;
+  int i;
+
+  assert (cids > 0);
+  for (i = 0; i < cids; i++)
+    {
+      struct res_entry **pp;
+
+      if (*resources == NULL)
+       {
+         *resources = (struct res_directory *) xmalloc (sizeof **resources);
+         (*resources)->characteristics = 0;
+         (*resources)->time = 0;
+         (*resources)->major = 0;
+         (*resources)->minor = 0;
+         (*resources)->entries = NULL;
+       }
+
+      for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
+       if (res_id_cmp ((*pp)->id, ids[i]) == 0)
+         break;
+
+      if (*pp != NULL)
+       re = *pp;
+      else
+       {
+         re = (struct res_entry *) xmalloc (sizeof *re);
+         re->next = NULL;
+         re->id = ids[i];
+         if ((i + 1) < cids)
+           {
+             re->subdir = 1;
+             re->u.dir = NULL;
+           }
+         else
+           {
+             re->subdir = 0;
+             re->u.res = NULL;
+           }
+
+         *pp = re;
+       }
+
+      if ((i + 1) < cids)
+       {
+         if (! re->subdir)
+           {
+             fprintf (stderr, "%s: ", program_name);
+             res_ids_print (stderr, i, ids);
+             fprintf (stderr, ": expected to be a directory\n");
+             xexit (1);
+           }
+
+         resources = &re->u.dir;
+       }
+    }
+
+  if (re->subdir)
+    {
+      fprintf (stderr, "%s: ", program_name);
+      res_ids_print (stderr, cids, ids);
+      fprintf (stderr, ": expected to be a leaf\n");
+      xexit (1);
+    }
+
+  if (re->u.res != NULL)
+    {
+      if (dupok)
+       return re->u.res;
+
+      fprintf (stderr, "%s: warning: ", program_name);
+      res_ids_print (stderr, cids, ids);
+      fprintf (stderr, ": duplicate value\n");
+    }
+
+  re->u.res = (struct res_resource *) xmalloc (sizeof (struct res_resource));
+
+  re->u.res->type = RES_TYPE_UNINITIALIZED;
+  memset (&re->u.res->res_info, 0, sizeof (struct res_res_info));
+  memset (&re->u.res->coff_info, 0, sizeof (struct res_coff_info));
+
+  return re->u.res;
+}
+
+/* Define a standard resource.  This is a version of define_resource
+   that just takes type, name, and language arguments.  */
+
+struct res_resource *
+define_standard_resource (resources, type, name, language, dupok)
+     struct res_directory **resources;
+     int type;
+     struct res_id name;
+     int language;
+     int dupok;
+{
+  struct res_id a[3];
+
+  a[0].named = 0;
+  a[0].u.id = type;
+  a[1] = name;
+  a[2].named = 0;
+  a[2].u.id = language;
+  return define_resource (resources, 3, a, dupok);
+}
+\f
+/* Return whether the dialog resource DIALOG is a DIALOG or a
+   DIALOGEX.  */
+
+int
+extended_dialog (dialog)
+     const struct dialog *dialog;
+{
+  const struct dialog_control *c;
+
+  if (dialog->ex != NULL)
+    return 1;
+
+  for (c = dialog->controls; c != NULL; c = c->next)
+    if (c->data != NULL || c->help != 0)
+      return 1;
+
+  return 0;
+}
+
+/* Return whether MENUITEMS are a MENU or a MENUEX.  */
+
+int
+extended_menu (menuitems)
+     const struct menuitem *menuitems;
+{
+  const struct menuitem *mi;
+
+  for (mi = menuitems; mi != NULL; mi = mi->next)
+    {
+      if (mi->help != 0 || mi->state != 0)
+       return 1;
+      if (mi->popup != NULL && mi->id != 0)
+       return 1;
+      if ((mi->type
+          & ~ (MENUITEM_CHECKED
+               | MENUITEM_GRAYED
+               | MENUITEM_HELP
+               | MENUITEM_INACTIVE
+               | MENUITEM_MENUBARBREAK
+               | MENUITEM_MENUBREAK))
+         != 0)
+       return 1;
+      if (mi->popup != NULL)
+       {
+         if (extended_menu (mi->popup))
+           return 1;
+       }
+    }
+
+  return 0;
+}
+\f
+/* Convert a string to a format type, or exit if it can't be done.  */
+
+static enum res_format
+format_from_name (name)
+     const char *name;
+{
+  const struct format_map *m;
+
+  for (m = format_names; m->name != NULL; m++)
+    if (strcasecmp (m->name, name) == 0)
+      break;
+
+  if (m->name == NULL)
+    {
+      fprintf (stderr, "%s: unknown format type `%s'\n", program_name, name);
+      fprintf (stderr, "%s: supported formats:", program_name);
+      for (m = format_names; m->name != NULL; m++)
+       fprintf (stderr, " %s", m->name);
+      fprintf (stderr, "\n");
+      xexit (1);
+    }
+
+  return m->format;
+}
+
+/* Work out a format type given a file name.  If INPUT is non-zero,
+   it's OK to look at the file itself.  */
+
+static enum res_format
+format_from_filename (filename, input)
+     const char *filename;
+     int input;
+{
+  const char *ext;
+  FILE *e;
+  unsigned char b1, b2, b3, b4, b5;
+  int magic;
+
+  /* If we have an extension, see if we recognize it as implying a
+     particular format.  */
+  ext = strrchr (filename, '.');
+  if (ext != NULL)
+    {
+      const struct format_map *m;
+
+      ++ext;
+      for (m = format_fileexts; m->name != NULL; m++)
+       if (strcasecmp (m->name, ext) == 0)
+         return m->format;
+    }
+
+  /* If we don't recognize the name of an output file, assume it's a
+     COFF file.  */
+
+  if (! input)
+    return RES_FORMAT_COFF;
+
+  /* Read the first few bytes of the file to see if we can guess what
+     it is.  */
+
+  e = fopen (filename, FOPEN_RB);
+  if (e == NULL)
+    fatal ("%s: %s", filename, strerror (errno));
+
+  b1 = getc (e);
+  b2 = getc (e);
+  b3 = getc (e);
+  b4 = getc (e);
+  b5 = getc (e);
+
+  fclose (e);
+
+  /* A PE executable starts with 0x4d 0x5a 0x90 0x00.  */
+  if (b1 == 0x4d && b2 == 0x5a && b3 == 0x90 && b4 == 0)
+    return RES_FORMAT_COFF;
+
+  /* A COFF .o file starts with a COFF magic number.  */
+  magic = (b2 << 8) | b1;
+  switch (magic)
+    {
+    case 0x14c: /* i386 */
+    case 0x166: /* MIPS */
+    case 0x184: /* Alpha */
+    case 0x268: /* 68k */
+    case 0x1f0: /* PowerPC */
+    case 0x290: /* PA */
+      return RES_FORMAT_COFF;
+    }
+
+  /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0.  */
+  if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
+    return RES_FORMAT_RES;
+
+  /* If every character is printable or space, assume it's an RC file.  */
+  if ((isprint (b1) || isspace (b1))
+      && (isprint (b2) || isspace (b2))
+      && (isprint (b3) || isspace (b3))
+      && (isprint (b4) || isspace (b4))
+      && (isprint (b5) || isspace (b5)))
+    return RES_FORMAT_RC;
+
+  /* Otherwise, we give up.  */
+  fatal ("can not determine type of file `%s'; use the -I option",
+        filename);
+
+  /* Return something to silence the compiler warning.  */
+  return RES_FORMAT_UNKNOWN;
+}
+
+/* Print a usage message and exit.  */
+
+static void
+usage (stream, status)
+     FILE *stream;
+     int status;
+{
+  fprintf (stream, "Usage: %s [options] [input-file] [output-file]\n",
+          program_name);
+  fprintf (stream, "\
+Options:\n\
+  -i FILE, --input FILE       Name input file\n\
+  -o FILE, --output FILE      Name output file\n\
+  -I FORMAT, --input-format FORMAT\n\
+                              Specify input format\n\
+  -O FORMAT, --output-format FORMAT\n\
+                              Specify output format\n\
+  -F TARGET, --target TARGET  Specify COFF target\n\
+  --preprocessor PROGRAM      Program to use to preprocess rc file\n\
+  --include-dir DIR           Include directory when preprocessing rc file\n\
+  --define SYM[=VAL]          Define SYM when preprocessing rc file\n\
+  --language VAL              Set language when reading rc file\n\
+#ifdef YYDEBUG
+  --yydebug                   Turn on parser debugging\n\
+#endif
+  --help                      Print this help message\n\
+  --version                   Print version information\n");
+  fprintf (stream, "\
+FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
+extension if not specified.  A single file name is an input file.\n\
+No input-file is stdin, default rc.  No output-file is stdout, default rc.\n");
+  list_supported_targets (program_name, stream);
+  if (status == 0)
+    fprintf (stream, "Report bugs to bug-gnu-utils@prep.ai.mit.edu\n");
+  exit (status);
+}
+
+/* The main function.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  char *input_filename;
+  char *output_filename;
+  enum res_format input_format;
+  enum res_format output_format;
+  char *target;
+  char *preprocessor;
+  char *preprocargs;
+  int language;
+  struct res_directory *resources;
+
+  program_name = argv[0];
+  xmalloc_set_program_name (program_name);
+
+  bfd_init ();
+  set_default_bfd_target ();
+
+  input_filename = NULL;
+  output_filename = NULL;
+  input_format = RES_FORMAT_UNKNOWN;
+  output_format = RES_FORMAT_UNKNOWN;
+  target = NULL;
+  preprocessor = NULL;
+  preprocargs = NULL;
+  language = -1;
+
+  while ((c = getopt_long (argc, argv, "i:o:I:O:F:", long_options,
+                          (int *) 0)) != EOF)
+    {
+      switch (c)
+       {
+       case 'i':
+         input_filename = optarg;
+         break;
+
+       case 'o':
+         output_filename = optarg;
+         break;
+
+       case 'I':
+         input_format = format_from_name (optarg);
+         break;
+
+       case 'O':
+         output_format = format_from_name (optarg);
+         break;
+
+       case 'F':
+         target = optarg;
+         break;
+
+       case OPTION_PREPROCESSOR:
+         preprocessor = optarg;
+         break;
+
+       case OPTION_DEFINE:
+         if (preprocargs == NULL)
+           {
+             preprocargs = xmalloc (strlen (optarg) + 3);
+             sprintf (preprocargs, "-D%s", optarg);
+           }
+         else
+           {
+             char *n;
+
+             n = xmalloc (strlen (preprocargs) + strlen (optarg) + 4);
+             sprintf (n, "%s -D%s", preprocargs, optarg);
+             free (preprocargs);
+             preprocargs = n;
+           }
+         break;
+
+       case OPTION_INCLUDE_DIR:
+         if (preprocargs == NULL)
+           {
+             preprocargs = xmalloc (strlen (optarg) + 3);
+             sprintf (preprocargs, "-I%s", optarg);
+           }
+         else
+           {
+             char *n;
+
+             n = xmalloc (strlen (preprocargs) + strlen (optarg) + 4);
+             sprintf (n, "%s -I%s", preprocargs, optarg);
+             free (preprocargs);
+             preprocargs = n;
+           }
+
+         {
+           struct include_dir *n, **pp;
+
+           n = (struct include_dir *) xmalloc (sizeof *n);
+           n->next = NULL;
+           n->dir = optarg;
+
+           for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
+             ;
+           *pp = n;
+         }
+
+         break;
+
+       case OPTION_LANGUAGE:
+         language = strtol (optarg, (char **) NULL, 16);
+         break;
+
+#ifdef YYDEBUG
+       case OPTION_YYDEBUG:
+         yydebug = 1;
+         break;
+#endif
+
+       case OPTION_HELP:
+         usage (stdout, 0);
+         break;
+
+       case OPTION_VERSION:
+         print_version ("windres");
+         break;
+
+       default:
+         usage (stderr, 1);
+         break;
+       }
+    }
+
+  if (input_filename == NULL && optind < argc)
+    {
+      input_filename = argv[optind];
+      ++optind;
+    }
+
+  if (output_filename == NULL && optind < argc)
+    {
+      output_filename = argv[optind];
+      ++optind;
+    }
+
+  if (argc != optind)
+    usage (stderr, 1);
+
+  if (input_format == RES_FORMAT_UNKNOWN)
+    {
+      if (input_filename == NULL)
+       input_format = RES_FORMAT_RC;
+      else
+       input_format = format_from_filename (input_filename, 1);
+    }
+
+  if (output_format == RES_FORMAT_UNKNOWN)
+    {
+      if (output_filename == NULL)
+       output_format = RES_FORMAT_RC;
+      else
+       output_format = format_from_filename (output_filename, 0);
+    }
+
+  /* Read the input file.  */
+
+  switch (input_format)
+    {
+    default:
+      abort ();
+    case RES_FORMAT_RC:
+      resources = read_rc_file (input_filename, preprocessor, preprocargs,
+                               language);
+      break;
+    case RES_FORMAT_RES:
+      resources = read_res_file (input_filename);
+      break;
+    case RES_FORMAT_COFF:
+      resources = read_coff_rsrc (input_filename, target);
+      break;
+    }
+
+  /* Write the output file.  */
+
+  switch (output_format)
+    {
+    default:
+      abort ();
+    case RES_FORMAT_RC:
+      write_rc_file (output_filename, resources);
+      break;
+    case RES_FORMAT_RES:
+      write_res_file (output_filename, resources);
+      break;
+    case RES_FORMAT_COFF:
+      write_coff_file (output_filename, target, resources);
+      break;
+    }
+
+  xexit (0);
+  return 0;
+}
+
+struct res_directory *
+read_res_file (filename)
+     const char *filename;
+{
+  fatal ("read_res_file unimplemented");
+  return NULL;
+}
+
+struct res_directory *
+read_coff_rsrc (filename, target)
+     const char *filename;
+     const char *target;
+{
+  fatal ("read_coff_rsrc unimplemented");
+  return NULL;
+}
+
+void
+write_res_file (filename, resources)
+     const char *filename;
+     const struct res_directory *resources;
+{
+  fatal ("write_res_file unimplemented");
+}
+
+void
+write_coff_file (filename, target, resources)
+     const char *filename;
+     const char *target;
+     const struct res_directory *resources;
+{
+  fatal ("write_coff_file unimplemented");
+}
diff --git a/binutils/windres.h b/binutils/windres.h
new file mode 100644 (file)
index 0000000..dbb9c5c
--- /dev/null
@@ -0,0 +1,820 @@
+/* windres.h -- header file for windres program.
+   Copyright 1997 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support.
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#include <ansidecl.h>
+
+/* This is the header file for the windres program.  It defines
+   structures and declares functions used within the program.  */
+
+/* We represent resources internally as a tree, similar to the tree
+   used in the .rsrc section of a COFF file.  The root is a
+   res_directory structure.  */
+
+struct res_directory
+{
+  /* Resource flags.  According to the MS docs, this is currently
+     always zero.  */
+  unsigned long characteristics;
+  /* Time/date stamp.  */
+  unsigned long time;
+  /* Major version number.  */
+  unsigned short major;
+  /* Minor version number.  */
+  unsigned short minor;
+  /* Directory entries.  */
+  struct res_entry *entries;
+};
+
+/* A resource ID is stored in a res_id structure.  */
+
+struct res_id
+{
+  /* Non-zero if this entry has a name rather than an ID.  */
+  unsigned int named : 1;
+  union
+  {
+    /* If the named field is non-zero, this is the name.  */
+    struct
+    {
+      /* Length of the name.  */
+      unsigned short length;
+      /* Pointer to the name, which is a Unicode string.  */
+      unsigned short *name;
+    } n;
+    /* If the named field is zero, this is the ID.  */
+    unsigned long id;
+  } u;
+};
+
+/* Each entry in the tree is a res_entry structure.  We mix
+   directories and resources because in a COFF file all entries in a
+   directory are sorted together, whether the entries are
+   subdirectories or resources.  */
+
+struct res_entry
+{
+  /* Next entry.  */
+  struct res_entry *next;
+  /* Resource ID.  */
+  struct res_id id;
+  /* Non-zero if this entry is a subdirectory rather than a leaf.  */
+  unsigned int subdir : 1;
+  union
+  {
+    /* If the subdir field is non-zero, this is a pointer to the
+       subdirectory.  */
+    struct res_directory *dir;
+    /* If the subdir field is zero, this is a pointer to the resource
+       data.  */
+    struct res_resource *res;
+  } u;
+};
+
+/* Types of resources.  */
+
+enum res_type
+{
+  RES_TYPE_UNINITIALIZED,
+  RES_TYPE_ACCELERATOR,
+  RES_TYPE_BITMAP,
+  RES_TYPE_CURSOR,
+  RES_TYPE_GROUP_CURSOR,
+  RES_TYPE_DIALOG,
+  RES_TYPE_FONT,
+  RES_TYPE_FONTDIR,
+  RES_TYPE_ICON,
+  RES_TYPE_GROUP_ICON,
+  RES_TYPE_MENU,
+  RES_TYPE_MESSAGETABLE,
+  RES_TYPE_RCDATA,
+  RES_TYPE_STRINGTABLE,
+  RES_TYPE_USERDATA,
+  RES_TYPE_VERSIONINFO
+};
+
+/* A res file and a COFF file store information differently.  The
+   res_info structures holds data which in a res file is stored with
+   each resource, but in a COFF file is stored elsewhere.  */
+
+struct res_res_info
+{
+  /* Language.  In a COFF file, the third level of the directory is
+     keyed by the language, so the language of a resource is defined
+     by its location in the resource tree.  */
+  unsigned short language;
+  /* Characteristics of the resource.  Entirely user defined.  In a
+     COFF file, the res_directory structure has a characteristics
+     field, but I don't know if it's related to the one in the res
+     file.  */
+  unsigned long characteristics;
+  /* Version of the resource.  Entirely user defined.  In a COFF file,
+     the res_directory structure has a characteristics field, but I
+     don't know if it's related to the one in the res file.  */
+  unsigned long version;
+  /* Memory flags.  This is a combination of the MEMFLAG values
+     defined below.  Most of these values are historical, and are not
+     meaningful for win32.  I don't think there is any way to store
+     this information in a COFF file.  */
+  unsigned short memflags;
+};
+
+/* Each resource in a COFF file has some information which can does
+   not appear in a res file.  */
+
+struct res_coff_info
+{
+  /* The code page used for the data.  I don't really know what this
+     should be.  */
+  unsigned long codepage;
+  /* A resource entry in a COFF file has a reserved field, which we
+     record here when reading a COFF file.  When writing a COFF file,
+     we set this field to zero.  */
+  unsigned long reserved;
+};
+
+/* Resource data is stored in a res_resource structure.  */
+
+struct res_resource
+{
+  /* The type of resource.  */
+  enum res_type type;
+  /* The data for the resource.  */
+  union
+  {
+    struct
+    {
+      unsigned long length;
+      unsigned char *data;
+    } data;
+    struct accelerator *acc;
+    struct cursor *cursor;
+    struct group_cursor *group_cursor;
+    struct dialog *dialog;
+    struct fontdir *fontdir;
+    struct group_icon *group_icon;
+    struct menuitem *menu;
+    struct rcdata_data *rcdata;
+    struct stringtable *stringtable;
+    struct rcdata_data *userdata;
+    struct versioninfo *versioninfo;
+  } u;
+  /* Information from a res file.  */
+  struct res_res_info res_info;
+  /* Information from a COFF file.  */
+  struct res_coff_info coff_info;
+};
+
+/* Memory flags in the memflags field of a struct res_resource.  */
+
+#define MEMFLAG_MOVEABLE       0x10
+#define MEMFLAG_PURE           0x20
+#define MEMFLAG_PRELOAD                0x40
+#define MEMFLAG_DISCARDABLE    0x1000
+
+/* Standard resource type codes.  These are used in the ID field of a
+   res_entry structure.  */
+
+#define RT_CURSOR               1
+#define RT_BITMAP               2
+#define RT_ICON                         3
+#define RT_MENU                         4
+#define RT_DIALOG               5
+#define RT_STRING               6
+#define RT_FONTDIR              7
+#define RT_FONT                         8
+#define RT_ACCELERATORS                 9
+#define RT_RCDATA              10
+#define RT_MESSAGETABLE                11
+#define RT_GROUP_CURSOR                12
+#define RT_GROUP_ICON          14
+#define RT_VERSION             16
+#define RT_DLGINCLUDE          17
+#define RT_PLUGPLAY            18
+#define RT_VXD                 19
+#define RT_ANICURSOR           21
+#define RT_ANIICON             22
+
+/* An accelerator resource is a linked list of these structures.  */
+
+struct accelerator
+{
+  /* Next accelerator.  */
+  struct accelerator *next;
+  /* Flags.  A combination of the ACC values defined below.  */
+  unsigned short flags;
+  /* Key value.  */
+  unsigned short key;
+  /* Resource ID.  */
+  unsigned short id;
+};
+
+/* Accelerator flags in the flags field of a struct accelerator.
+   These are the same values that appear in a res file.  I hope.  */
+
+#define ACC_VIRTKEY    0x01
+#define ACC_NOINVERT   0x02
+#define ACC_SHIFT      0x04
+#define ACC_CONTROL    0x08
+#define ACC_ALT                0x10
+#define ACC_LAST       0x80
+
+/* A cursor resource.  */
+
+struct cursor
+{
+  /* X coordinate of hotspot.  */
+  short xhotspot;
+  /* Y coordinate of hotspot.  */
+  short yhotspot;
+  /* Length of bitmap data.  */
+  unsigned long length;
+  /* Data.  */
+  unsigned char *data;
+};
+
+/* A group_cursor resource is a list of group_cursor structures.  */
+
+struct group_cursor
+{
+  /* Next cursor in group.  */
+  struct group_cursor *next;
+  /* Width.  */
+  unsigned short width;
+  /* Height.  */
+  unsigned short height;
+  /* Planes.  */
+  unsigned short planes;
+  /* Bits per pixel.  */
+  unsigned short bits;
+  /* Number of bytes in cursor resource.  */
+  unsigned long bytes;
+  /* Index of cursor resource.  */
+  unsigned short index;
+};
+
+/* A dialog resource.  */
+
+struct dialog
+{
+  /* Basic window style.  */
+  unsigned long style;
+  /* Extended window style.  */
+  unsigned long exstyle;
+  /* X coordinate.  */
+  unsigned short x;
+  /* Y coordinate.  */
+  unsigned short y;
+  /* Width.  */
+  unsigned short width;
+  /* Height.  */
+  unsigned short height;
+  /* Menu name.  */
+  struct res_id menu;
+  /* Class name.  */
+  struct res_id class;
+  /* Caption.  */
+  char *caption;
+  /* Font point size.  */
+  unsigned short pointsize;
+  /* Font name.  */
+  char *font;
+  /* Extended information for a dialogex.  */
+  struct dialog_ex *ex;
+  /* Controls.  */
+  struct dialog_control *controls;
+};
+
+/* An extended dialog has additional information.  */
+
+struct dialog_ex
+{
+  /* Help ID.  */
+  unsigned long help;
+  /* Font weight.  */
+  unsigned short weight;
+  /* Whether the font is italic.  */
+  unsigned short italic;
+};
+
+/* Window style flags, from the winsup Defines.h header file.  These
+   can appear in the style field of a struct dialog or a struct
+   dialog_control.  */
+
+#define CW_USEDEFAULT  (0x80000000)
+#define WS_BORDER      (0x800000L)
+#define WS_CAPTION     (0xc00000L)
+#define WS_CHILD       (0x40000000L)
+#define WS_CHILDWINDOW (0x40000000L)
+#define WS_CLIPCHILDREN        (0x2000000L)
+#define WS_CLIPSIBLINGS        (0x4000000L)
+#define WS_DISABLED    (0x8000000L)
+#define WS_DLGFRAME    (0x400000L)
+#define WS_GROUP       (0x20000L)
+#define WS_HSCROLL     (0x100000L)
+#define WS_ICONIC      (0x20000000L)
+#define WS_MAXIMIZE    (0x1000000L)
+#define WS_MAXIMIZEBOX (0x10000L)
+#define WS_MINIMIZE    (0x20000000L)
+#define WS_MINIMIZEBOX (0x20000L)
+#define WS_OVERLAPPED  (0L)
+#define WS_OVERLAPPEDWINDOW    (0xcf0000L)
+#define WS_POPUP       (0x80000000L)
+#define WS_POPUPWINDOW (0x80880000L)
+#define WS_SIZEBOX     (0x40000L)
+#define WS_SYSMENU     (0x80000L)
+#define WS_TABSTOP     (0x10000L)
+#define WS_THICKFRAME  (0x40000L)
+#define WS_TILED       (0L)
+#define WS_TILEDWINDOW (0xcf0000L)
+#define WS_VISIBLE     (0x10000000L)
+#define WS_VSCROLL     (0x200000L)
+#define MDIS_ALLCHILDSTYLES    (0x1)
+#define BS_3STATE      (0x5L)
+#define BS_AUTO3STATE  (0x6L)
+#define BS_AUTOCHECKBOX        (0x3L)
+#define BS_AUTORADIOBUTTON     (0x9L)
+#define BS_BITMAP      (0x80L)
+#define BS_BOTTOM      (0x800L)
+#define BS_CENTER      (0x300L)
+#define BS_CHECKBOX    (0x2L)
+#define BS_DEFPUSHBUTTON       (0x1L)
+#define BS_GROUPBOX    (0x7L)
+#define BS_ICON        (0x40L)
+#define BS_LEFT        (0x100L)
+#define BS_LEFTTEXT    (0x20L)
+#define BS_MULTILINE   (0x2000L)
+#define BS_NOTIFY      (0x4000L)
+#define BS_OWNERDRAW   (0xbL)
+#define BS_PUSHBOX     (0xcL)          /* FIXME!  What should this be?  */
+#define BS_PUSHBUTTON  (0L)
+#define BS_PUSHLIKE    (0x1000L)
+#define BS_RADIOBUTTON (0x4L)
+#define BS_RIGHT       (0x200L)
+#define BS_RIGHTBUTTON (0x20L)
+#define BS_TEXT        (0L)
+#define BS_TOP (0x400L)
+#define BS_USERBUTTON  (0x8L)
+#define BS_VCENTER     (0xc00L)
+#define CBS_AUTOHSCROLL        (0x40L)
+#define CBS_DISABLENOSCROLL    (0x800L)
+#define CBS_DROPDOWN   (0x2L)
+#define CBS_DROPDOWNLIST       (0x3L)
+#define CBS_HASSTRINGS (0x200L)
+#define CBS_LOWERCASE  (0x4000L)
+#define CBS_NOINTEGRALHEIGHT   (0x400L)
+#define CBS_OEMCONVERT (0x80L)
+#define CBS_OWNERDRAWFIXED     (0x10L)
+#define CBS_OWNERDRAWVARIABLE  (0x20L)
+#define CBS_SIMPLE     (0x1L)
+#define CBS_SORT       (0x100L)
+#define CBS_UPPERCASE  (0x2000L)
+#define ES_AUTOHSCROLL (0x80L)
+#define ES_AUTOVSCROLL (0x40L)
+#define ES_CENTER      (0x1L)
+#define ES_LEFT        (0L)
+#define ES_LOWERCASE   (0x10L)
+#define ES_MULTILINE   (0x4L)
+#define ES_NOHIDESEL   (0x100L)
+#define ES_NUMBER      (0x2000L)
+#define ES_OEMCONVERT  (0x400L)
+#define ES_PASSWORD    (0x20L)
+#define ES_READONLY    (0x800L)
+#define ES_RIGHT       (0x2L)
+#define ES_UPPERCASE   (0x8L)
+#define ES_WANTRETURN  (0x1000L)
+#define LBS_DISABLENOSCROLL    (0x1000L)
+#define LBS_EXTENDEDSEL        (0x800L)
+#define LBS_HASSTRINGS (0x40L)
+#define LBS_MULTICOLUMN        (0x200L)
+#define LBS_MULTIPLESEL        (0x8L)
+#define LBS_NODATA     (0x2000L)
+#define LBS_NOINTEGRALHEIGHT   (0x100L)
+#define LBS_NOREDRAW   (0x4L)
+#define LBS_NOSEL      (0x4000L)
+#define LBS_NOTIFY     (0x1L)
+#define LBS_OWNERDRAWFIXED     (0x10L)
+#define LBS_OWNERDRAWVARIABLE  (0x20L)
+#define LBS_SORT       (0x2L)
+#define LBS_STANDARD   (0xa00003L)
+#define LBS_USETABSTOPS        (0x80L)
+#define LBS_WANTKEYBOARDINPUT  (0x400L)
+#define SBS_BOTTOMALIGN        (0x4L)
+#define SBS_HORZ       (0L)
+#define SBS_LEFTALIGN  (0x2L)
+#define SBS_RIGHTALIGN (0x4L)
+#define SBS_SIZEBOX    (0x8L)
+#define SBS_SIZEBOXBOTTOMRIGHTALIGN    (0x4L)
+#define SBS_SIZEBOXTOPLEFTALIGN        (0x2L)
+#define SBS_SIZEGRIP   (0x10L)
+#define SBS_TOPALIGN   (0x2L)
+#define SBS_VERT       (0x1L)
+#define SS_BITMAP      (0xeL)
+#define SS_BLACKFRAME  (0x7L)
+#define SS_BLACKRECT   (0x4L)
+#define SS_CENTER      (0x1L)
+#define SS_CENTERIMAGE (0x200L)
+#define SS_ENHMETAFILE (0xfL)
+#define SS_ETCHEDFRAME (0x12L)
+#define SS_ETCHEDHORZ  (0x10L)
+#define SS_ETCHEDVERT  (0x11L)
+#define SS_GRAYFRAME   (0x8L)
+#define SS_GRAYRECT    (0x5L)
+#define SS_ICON        (0x3L)
+#define SS_LEFT        (0L)
+#define SS_LEFTNOWORDWRAP      (0xcL)
+#define SS_NOPREFIX    (0x80L)
+#define SS_NOTIFY      (0x100L)
+#define SS_OWNERDRAW   (0xdL)
+#define SS_REALSIZEIMAGE       (0x800L)
+#define SS_RIGHT       (0x2L)
+#define SS_RIGHTJUST   (0x400L)
+#define SS_SIMPLE      (0xbL)
+#define SS_SUNKEN      (0x1000L)
+#define SS_USERITEM     (0xaL)
+#define SS_WHITEFRAME  (0x9L)
+#define SS_WHITERECT   (0x6L)
+#define DS_3DLOOK      (0x4L)
+#define DS_ABSALIGN    (0x1L)
+#define DS_CENTER      (0x800L)
+#define DS_CENTERMOUSE (0x1000L)
+#define DS_CONTEXTHELP (0x2000L)
+#define DS_CONTROL     (0x400L)
+#define DS_FIXEDSYS    (0x8L)
+#define DS_LOCALEDIT   (0x20L)
+#define DS_MODALFRAME  (0x80L)
+#define DS_NOFAILCREATE        (0x10L)
+#define DS_NOIDLEMSG   (0x100L)
+#define DS_SETFONT     (0x40L)
+#define DS_SETFOREGROUND       (0x200L)
+#define DS_SYSMODAL    (0x2L)
+
+/* A dialog control.  */
+
+struct dialog_control
+{
+  /* Next control.  */
+  struct dialog_control *next;
+  /* ID.  */
+  unsigned short id;
+  /* Style.  */
+  unsigned long style;
+  /* Extended style.  */
+  unsigned long exstyle;
+  /* X coordinate.  */
+  unsigned short x;
+  /* Y coordinate.  */
+  unsigned short y;
+  /* Width.  */
+  unsigned short width;
+  /* Height.  */
+  unsigned short height;
+  /* Class name.  */
+  struct res_id class;
+  /* Associated text.  */
+  struct res_id text;
+  /* Extra data for the window procedure.  */
+  struct rcdata_data *data;
+  /* Help ID.  Only used in an extended dialog.  */
+  unsigned long help;
+};
+
+/* Control classes.  These can be used as the ID field in a struct
+   dialog_control.  */
+
+#define CTL_BUTTON     0x80
+#define CTL_EDIT       0x81
+#define CTL_STATIC     0x82
+#define CTL_LISTBOX    0x83
+#define CTL_SCROLLBAR  0x84
+#define CTL_COMBOBOX   0x85
+
+/* A fontdir resource is a list of fontdir structures.  */
+
+struct fontdir
+{
+  struct fontdir *next;
+  /* Index of font entry.  */
+  short index;
+  /* Length of font information.  */
+  unsigned long length;
+  /* Font information. */
+  unsigned char *data;
+};
+
+/* A group_icon resource is a list of group_icon structures.  */
+
+struct group_icon
+{
+  /* Next icon in group.  */
+  struct group_icon *next;
+  /* Width.  */
+  unsigned char width;
+  /* Height.  */
+  unsigned char height;
+  /* Color count.  */
+  unsigned char colors;
+  /* Planes.  */
+  unsigned short planes;
+  /* Bits per pixel.  */
+  unsigned short bits;
+  /* Number of bytes in cursor resource.  */
+  unsigned long bytes;
+  /* Index of cursor resource.  */
+  unsigned short index;
+};
+
+/* A menu resource is a list of menuitem structures.  */
+
+struct menuitem
+{
+  /* Next menuitem.  */
+  struct menuitem *next;
+  /* Type.  In a normal menu, rather than a menuex, this is the flags
+     field.  */
+  unsigned long type;
+  /* State.  This is only used in a menuex.  */
+  unsigned long state;
+  /* Id.  */
+  unsigned short id;
+  /* Text.  */
+  char *text;
+  /* Popup menu items for a popup.  */
+  struct menuitem *popup;
+  /* Help ID.  This is only used in a menuex.  */
+  unsigned long help;
+};
+
+/* Menu item flags.  These can appear in the flags field of a struct
+   menuitem.  */
+
+#define MENUITEM_GRAYED                0x001
+#define MENUITEM_INACTIVE      0x002
+#define MENUITEM_BITMAP                0x004
+#define MENUITEM_OWNERDRAW     0x100
+#define MENUITEM_CHECKED       0x008
+#define MENUITEM_POPUP         0x010
+#define MENUITEM_MENUBARBREAK  0x020
+#define MENUITEM_MENUBREAK     0x040
+#define MENUITEM_HELP         0x4000
+
+/* An rcdata resource is a pointer to an rcdata_data structure.  */
+
+struct rcdata_data
+{
+  /* First data item.  */
+  struct rcdata_item *first;
+  /* Last data item.  */
+  struct rcdata_item *last;
+};
+
+/* For an rcdata resource we keep a list of rcdata_item structures.  */
+
+struct rcdata_item
+{
+  /* Next data item.  */
+  struct rcdata_item *next;
+  /* Type of data.  */
+  enum
+  {
+    RCDATA_WORD,
+    RCDATA_DWORD,
+    RCDATA_STRING,
+    RCDATA_WSTRING,
+    RCDATA_BUFFER
+  } type;
+  union
+  {
+    unsigned int word;
+    unsigned long dword;
+    char *string;
+    unsigned short *wstring;
+    struct
+    {
+      unsigned long length;
+      unsigned char *data;
+    } buffer;
+  } u;
+};
+
+/* A stringtable resource is a pointer to a stringtable structure.  */
+
+struct stringtable
+{
+  /* Each stringtable resource is a list of 16 unicode strings.  */
+  struct
+  {
+    /* Length of string.  */
+    unsigned short length;
+    /* String data if length > 0.  */
+    unsigned short *string;
+  } strings[16];
+};
+
+/* A versioninfo resource points to a versioninfo structure.  */
+
+struct versioninfo
+{
+  /* Fixed version information.  */
+  struct fixed_versioninfo *fixed;
+  /* Variable version information.  */
+  struct ver_info *var;
+};
+
+/* The fixed portion of a versioninfo resource.  */
+
+struct fixed_versioninfo
+{
+  /* The file version, which is two 32 bit integers.  */
+  unsigned long file_version_ms;
+  unsigned long file_version_ls;
+  /* The product version, which is two 32 bit integers.  */
+  unsigned long product_version_ms;
+  unsigned long product_version_ls;
+  /* The file flags mask.  */
+  unsigned long file_flags_mask;
+  /* The file flags.  */
+  unsigned long file_flags;
+  /* The OS type.  */
+  unsigned long file_os;
+  /* The file type.  */
+  unsigned long file_type;
+  /* The file subtype.  */
+  unsigned long file_subtype;
+  /* The date, which in Windows is two 32 bit integers.  */
+  unsigned long file_date_ms;
+  unsigned long file_date_ls;
+};
+
+/* A list of variable version information.  */
+
+struct ver_info
+{
+  /* Next item.  */
+  struct ver_info *next;
+  /* Type of data.  */
+  enum { VERINFO_STRING, VERINFO_VAR } type;
+  union
+  {
+    /* StringFileInfo data.  */
+    struct
+    {
+      /* Language.  */
+      unsigned short *language;
+      /* Strings.  */
+      struct ver_stringinfo *strings;
+    } string;
+    /* VarFileInfo data.  */
+    struct
+    {
+      /* Key.  */
+      unsigned short *key;
+      /* Values.  */
+      struct ver_varinfo *var;
+    } var;
+  } u;
+};
+
+/* A list of string version information.  */
+
+struct ver_stringinfo
+{
+  /* Next string.  */
+  struct ver_stringinfo *next;
+  /* Key.  */
+  unsigned short *key;
+  /* Value.  */
+  unsigned short *value;
+};
+
+/* A list of variable version information.  */
+
+struct ver_varinfo
+{
+  /* Next item.  */
+  struct ver_varinfo *next;
+  /* Language ID.  */
+  unsigned short language;
+  /* Character set ID.  */
+  unsigned short charset;
+};
+
+/* Function declarations.  */
+
+extern struct res_directory *read_rc_file
+  PARAMS ((const char *, const char *, const char *, int));
+extern struct res_directory *read_res_file PARAMS ((const char *));
+extern struct res_directory *read_coff_rsrc
+  PARAMS ((const char *, const char *));
+extern void write_rc_file
+  PARAMS ((const char *, const struct res_directory *));
+extern void write_res_file
+  PARAMS ((const char *, const struct res_directory *));
+extern void write_coff_file
+  PARAMS ((const char *, const char *, const struct res_directory *));
+
+extern FILE *open_file_search
+  PARAMS ((const char *, const char *, const char *, char **));
+
+/* Resource ID handling.  */
+
+extern int res_id_cmp PARAMS ((struct res_id, struct res_id));
+extern void res_id_print PARAMS ((FILE *, struct res_id, int));
+extern void res_ids_print PARAMS ((FILE *, int, const struct res_id *));
+extern void res_string_to_id PARAMS ((struct res_id *, const char *));
+
+/* Unicode support.  */
+
+extern void unicode_from_ascii
+  PARAMS ((unsigned short *, unsigned short **, const char *));
+extern void unicode_print PARAMS ((FILE *, const unsigned short *, int));
+
+/* Manipulation of the resource tree.  */
+
+extern struct res_resource *define_resource
+  PARAMS ((struct res_directory **, int, const struct res_id *, int));
+extern struct res_resource *define_standard_resource
+  PARAMS ((struct res_directory **, int, struct res_id, int, int));
+
+extern int extended_dialog PARAMS ((const struct dialog *));
+extern int extended_menu PARAMS ((const struct menuitem *));
+
+/* Communication between the rc file support and the parser and lexer.  */
+
+extern int yydebug;
+extern FILE *yyin;
+extern char *rc_filename;
+extern int rc_lineno;
+extern int yyparse PARAMS ((void));
+extern int yylex PARAMS ((void));
+extern void yyerror PARAMS ((const char *));
+extern void rcparse_warning PARAMS ((const char *));
+extern void rcparse_set_language PARAMS ((int));
+
+extern void define_accelerator
+  PARAMS ((struct res_id, const struct res_res_info *, struct accelerator *));
+extern void define_bitmap
+  PARAMS ((struct res_id, const struct res_res_info *, const char *));
+extern void define_cursor
+  PARAMS ((struct res_id, const struct res_res_info *, const char *));
+extern void define_dialog
+  PARAMS ((struct res_id, const struct res_res_info *, const struct dialog *));
+extern struct dialog_control *define_control
+  PARAMS ((char *, unsigned long, unsigned long, unsigned long,
+          unsigned long, unsigned long, unsigned long, unsigned long,
+          unsigned long));
+extern void define_font
+  PARAMS ((struct res_id, const struct res_res_info *, const char *));
+extern void define_icon
+  PARAMS ((struct res_id, const struct res_res_info *, const char *));
+extern void define_menu
+  PARAMS ((struct res_id, const struct res_res_info *, struct menuitem *));
+extern struct menuitem *define_menuitem
+  PARAMS ((char *, int, unsigned long, unsigned long, unsigned long,
+          struct menuitem *));
+extern void define_messagetable
+  PARAMS ((struct res_id, const struct res_res_info *, const char *));
+extern void define_rcdata
+  PARAMS ((struct res_id, const struct res_res_info *, struct rcdata_data *));
+extern struct rcdata_data *append_rcdata_item
+  PARAMS ((struct rcdata_data *, struct rcdata_item *));
+extern struct rcdata_data *append_rcdata_string
+  PARAMS ((struct rcdata_data *, char *));
+extern struct rcdata_data *append_rcdata_number
+  PARAMS ((struct rcdata_data *, unsigned long, int));
+extern void define_stringtable
+  PARAMS ((const struct res_res_info *, unsigned long, char *));
+extern void define_user_data
+  PARAMS ((struct res_id, struct res_id, const struct res_res_info *,
+          struct rcdata_data *));
+extern void define_user_file
+  PARAMS ((struct res_id, struct res_id, const struct res_res_info *,
+          const char *));
+extern void define_versioninfo
+  PARAMS ((struct res_id, int, struct fixed_versioninfo *,
+          struct ver_info *));
+extern struct ver_info *append_ver_stringfileinfo
+  PARAMS ((struct ver_info *, char *, struct ver_stringinfo *));
+extern struct ver_info *append_ver_varfileinfo
+  PARAMS ((struct ver_info *, char *, struct ver_varinfo *));
+extern struct ver_stringinfo *append_verval
+  PARAMS ((struct ver_stringinfo *, char *, char *));
+extern struct ver_varinfo *append_vertrans
+  PARAMS ((struct ver_varinfo *, unsigned long, unsigned long));