aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binutils/.Sanitize5
-rw-r--r--binutils/ChangeLog20
-rw-r--r--binutils/Makefile.in55
-rwxr-xr-xbinutils/configure157
-rw-r--r--binutils/configure.in16
-rw-r--r--binutils/rclex.l320
-rw-r--r--binutils/rcparse.y1513
-rw-r--r--binutils/resrc.c2220
-rw-r--r--binutils/windres.c912
-rw-r--r--binutils/windres.h820
10 files changed, 5953 insertions, 85 deletions
diff --git a/binutils/.Sanitize b/binutils/.Sanitize
index f253b50..5bae795 100644
--- a/binutils/.Sanitize
+++ b/binutils/.Sanitize
@@ -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:
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 1ab9055..2a685dc 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -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.
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index 985e226..65d25f7 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -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
diff --git a/binutils/configure b/binutils/configure
index 066b290..57ba36e 100755
--- a/binutils/configure
+++ b/binutils/configure
@@ -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
diff --git a/binutils/configure.in b/binutils/configure.in
index f5ce9d6..67fdb06 100644
--- a/binutils/configure.in
+++ b/binutils/configure.in
@@ -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
index 0000000..eb36bf6
--- /dev/null
+++ b/binutils/rclex.l
@@ -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
index 0000000..56c6db8
--- /dev/null
+++ b/binutils/rcparse.y
@@ -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
index 0000000..64c6c78
--- /dev/null
+++ b/binutils/resrc.c
@@ -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));
+
+/* 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);
+}
+
+/* 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;
+}
+
+/* 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
index 0000000..d08fb97
--- /dev/null
+++ b/binutils/windres.c
@@ -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));
+
+/* 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;
+}
+
+/* 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);
+ }
+}
+
+/* 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);
+}
+
+/* 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;
+}
+
+/* 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
index 0000000..dbb9c5c
--- /dev/null
+++ b/binutils/windres.h
@@ -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));