2003-05-20 Michal Ludvig <mludvig@suse.cz>
[binutils-gdb.git] / binutils / resrc.c
index 60cf4edd8e31d0b3d690a63ff963f7953c4804fd..a8955976363c89625e027041082d9efded813e35 100644 (file)
@@ -1,5 +1,5 @@
 /* resrc.c -- read and write Windows rc files.
-   Copyright 1997 Free Software Foundation, Inc.
+   Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GNU Binutils.
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA.  */
 
-/* This file contains function that read and write Windows rc files.
+/* This file contains functions that read and write Windows rc files.
    These are text files that represent resources.  */
 
 #include "bfd.h"
 #include "bucomm.h"
 #include "libiberty.h"
+#include "safe-ctype.h"
 #include "windres.h"
 
 #include <assert.h>
-#include <ctype.h>
+#include <errno.h>
 #include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#else /* ! HAVE_SYS_WAIT_H */
+#if ! defined (_WIN32) || defined (__CYGWIN__)
+#ifndef WIFEXITED
+#define WIFEXITED(w)   (((w)&0377) == 0)
+#endif
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(w)    ((w) & 0177)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(w) (((w) >> 8) & 0377)
+#endif
+#else /* defined (_WIN32) && ! defined (__CYGWIN__) */
+#ifndef WIFEXITED
+#define WIFEXITED(w)   (((w) & 0xff) == 0)
+#endif
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(w)    ((w) & 0x7f)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
+#endif
+#endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
+#endif /* ! HAVE_SYS_WAIT_H */
+
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+
+#if defined (_WIN32) && ! defined (__CYGWIN__)
+#define popen _popen
+#define pclose _pclose
+#endif
 
 /* The default preprocessor.  */
 
-#define DEFAULT_PREPROCESSOR "gcc -E -xc-header -DRC_INVOKED"
+#define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
 
 /* We read the directory entries in a cursor or icon file into
    instances of this structure.  */
@@ -81,6 +126,15 @@ int rc_lineno;
 
 static FILE *cpp_pipe;
 
+/* The temporary file used if we're not using popen, so we can delete it
+   if we exit.  */
+
+static char *cpp_temp_file;
+
+/* Input stream is either a file or a pipe.  */
+
+static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
+
 /* As we read the rc file, we attach information to this structure.  */
 
 static struct res_directory *resources;
@@ -107,7 +161,11 @@ static int icons;
 
 /* Local functions.  */
 
-static void close_pipe PARAMS ((void));
+static int run_cmd PARAMS ((char *, const char *));
+static FILE *open_input_stream PARAMS ((char *));
+static FILE *look_for_default PARAMS ((char *, const char *, int,
+                                      const char *, const char *));
+static void close_input_stream 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 *));
@@ -115,37 +173,307 @@ static void get_data
   PARAMS ((FILE *, unsigned char *, unsigned long, const char *));
 static void define_fontdirs PARAMS ((void));
 \f
+/* Run `cmd' and redirect the output to `redir'.  */
+
+static int
+run_cmd (cmd, redir)
+     char *cmd;
+     const char *redir;
+{
+  char *s;
+  int pid, wait_status, retcode;
+  int i;
+  const char **argv;
+  char *errmsg_fmt, *errmsg_arg;
+  char *temp_base = choose_temp_base ();
+  int in_quote;
+  char sep;
+  int redir_handle = -1;
+  int stdout_save = -1;
+
+  /* Count the args.  */
+  i = 0;
+
+  for (s = cmd; *s; s++)
+    if (*s == ' ')
+      i++;
+
+  i++;
+  argv = alloca (sizeof (char *) * (i + 3));
+  i = 0;
+  s = cmd;
+
+  while (1)
+    {
+      while (*s == ' ' && *s != 0)
+       s++;
+
+      if (*s == 0)
+       break;
+
+      in_quote = (*s == '\'' || *s == '"');
+      sep = (in_quote) ? *s++ : ' ';
+      argv[i++] = s;
+
+      while (*s != sep && *s != 0)
+       s++;
+
+      if (*s == 0)
+       break;
+
+      *s++ = 0;
+
+      if (in_quote)
+       s++;
+    }
+  argv[i++] = NULL;
+
+  /* Setup the redirection.  We can't use the usual fork/exec and redirect
+     since we may be running on non-POSIX Windows host.  */
+
+  fflush (stdout);
+  fflush (stderr);
+
+  /* Open temporary output file.  */
+  redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+  if (redir_handle == -1)
+    fatal (_("can't open temporary file `%s': %s"), redir,
+          strerror (errno));
+
+  /* Duplicate the stdout file handle so it can be restored later.  */
+  stdout_save = dup (STDOUT_FILENO);
+  if (stdout_save == -1)
+    fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
+
+  /* Redirect stdout to our output file.  */
+  dup2 (redir_handle, STDOUT_FILENO);
+
+  pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
+                 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
+
+  /* Restore stdout to its previous setting.  */
+  dup2 (stdout_save, STDOUT_FILENO);
+
+  /* Close reponse file.  */
+  close (redir_handle);
+
+  if (pid == -1)
+    {
+      fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
+      return 1;
+    }
+
+  retcode = 0;
+  pid = pwait (pid, &wait_status, 0);
+
+  if (pid == -1)
+    {
+      fatal (_("wait: %s"), strerror (errno));
+      retcode = 1;
+    }
+  else if (WIFSIGNALED (wait_status))
+    {
+      fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
+      retcode = 1;
+    }
+  else if (WIFEXITED (wait_status))
+    {
+      if (WEXITSTATUS (wait_status) != 0)
+       {
+         fatal (_("%s exited with status %d"), cmd,
+                WEXITSTATUS (wait_status));
+         retcode = 1;
+       }
+    }
+  else
+    retcode = 1;
+
+  return retcode;
+}
+
+static FILE *
+open_input_stream (cmd)
+     char *cmd;
+{
+  if (istream_type == ISTREAM_FILE)
+    {
+      char *fileprefix;
+
+      fileprefix = choose_temp_base ();
+      cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
+      sprintf (cpp_temp_file, "%s.irc", fileprefix);
+      free (fileprefix);
+
+      if (run_cmd (cmd, cpp_temp_file))
+       fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
+
+      cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
+      if (cpp_pipe == NULL)
+       fatal (_("can't open temporary file `%s': %s"),
+              cpp_temp_file, strerror (errno));
+
+      if (verbose)
+       fprintf (stderr,
+                _("Using temporary file `%s' to read preprocessor output\n"),
+                cpp_temp_file);
+    }
+  else
+    {
+      cpp_pipe = popen (cmd, FOPEN_RT);
+      if (cpp_pipe == NULL)
+       fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
+      if (verbose)
+       fprintf (stderr, _("Using popen to read preprocessor output\n"));
+    }
+
+  xatexit (close_input_stream);
+  return cpp_pipe;
+}
+
+/* look for the preprocessor program */
+
+static FILE *
+look_for_default (cmd, prefix, end_prefix, preprocargs, filename)
+     char *cmd;
+     const char *prefix;
+     int end_prefix;
+     const char *preprocargs;
+     const char *filename;
+{
+  char *space;
+  int found;
+  struct stat s;
+
+  strcpy (cmd, prefix);
+
+  sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
+  space = strchr (cmd + end_prefix, ' ');
+  if (space)
+    *space = 0;
+
+  if (
+#if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
+      strchr (cmd, '\\') ||
+#endif
+      strchr (cmd, '/'))
+    {
+      found = (stat (cmd, &s) == 0
+#ifdef HAVE_EXECUTABLE_SUFFIX
+              || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
+#endif
+              );
+
+      if (! found)
+       {
+         if (verbose)
+           fprintf (stderr, _("Tried `%s'\n"), cmd);
+         return NULL;
+       }
+    }
+
+  strcpy (cmd, prefix);
+
+  sprintf (cmd + end_prefix, "%s %s %s",
+          DEFAULT_PREPROCESSOR, preprocargs, filename);
+
+  if (verbose)
+    fprintf (stderr, _("Using `%s'\n"), cmd);
+
+  cpp_pipe = open_input_stream (cmd);
+  return cpp_pipe;
+}
+
 /* Read an rc file.  */
 
 struct res_directory *
-read_rc_file (filename, preprocessor, preprocargs, language)
+read_rc_file (filename, preprocessor, preprocargs, language, use_temp_file)
      const char *filename;
      const char *preprocessor;
      const char *preprocargs;
      int language;
+     int use_temp_file;
 {
   char *cmd;
 
-  if (preprocessor == NULL)
-    preprocessor = DEFAULT_PREPROCESSOR;
+  istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
 
   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);
+  if (preprocessor)
+    {
+      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));
-  free (cmd);
+      cpp_pipe = open_input_stream (cmd);
+    }
+  else
+    {
+      char *dash, *slash, *cp;
+
+      preprocessor = DEFAULT_PREPROCESSOR;
+
+      cmd = xmalloc (strlen (program_name)
+                    + strlen (preprocessor)
+                    + strlen (preprocargs)
+                    + strlen (filename)
+#ifdef HAVE_EXECUTABLE_SUFFIX
+                    + strlen (EXECUTABLE_SUFFIX)
+#endif
+                    + 10);
+
+
+      dash = slash = 0;
+      for (cp = program_name; *cp; cp++)
+       {
+         if (*cp == '-')
+           dash = cp;
+         if (
+#if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
+             *cp == ':' || *cp == '\\' ||
+#endif
+             *cp == '/')
+           {
+             slash = cp;
+             dash = 0;
+           }
+       }
 
-  xatexit (close_pipe);
+      cpp_pipe = 0;
+
+      if (dash)
+       {
+         /* First, try looking for a prefixed gcc in the windres
+            directory, with the same prefix as windres */
+
+         cpp_pipe = look_for_default (cmd, program_name, dash-program_name+1,
+                                      preprocargs, filename);
+       }
+
+      if (slash && !cpp_pipe)
+       {
+         /* Next, try looking for a gcc in the same directory as
+             that windres */
+
+         cpp_pipe = look_for_default (cmd, program_name, slash-program_name+1,
+                                      preprocargs, filename);
+       }
+
+      if (!cpp_pipe)
+       {
+         /* Sigh, try the default */
+
+         cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
+       }
+
+    }
+
+  free (cmd);
 
   rc_filename = xstrdup (filename);
   rc_lineno = 1;
@@ -153,10 +481,9 @@ read_rc_file (filename, preprocessor, preprocargs, language)
     rcparse_set_language (language);
   yyin = cpp_pipe;
   yyparse ();
+  rcparse_discard_strings ();
 
-  if (pclose (cpp_pipe) != 0)
-    fprintf (stderr, "%s: warning: preprocessor failed\n", program_name);
-  cpp_pipe = NULL;
+  close_input_stream ();
 
   if (fontdirs != NULL)
     define_fontdirs ();
@@ -167,13 +494,34 @@ read_rc_file (filename, preprocessor, preprocargs, language)
   return resources;
 }
 
-/* Close the pipe if it is open.  This is called via xatexit.  */
+/* Close the input stream if it is open.  */
 
-void
-close_pipe ()
+static void
+close_input_stream ()
 {
-  if (cpp_pipe != NULL)
-    pclose (cpp_pipe);
+  if (istream_type == ISTREAM_FILE)
+    {
+      if (cpp_pipe != NULL)
+       fclose (cpp_pipe);
+
+      if (cpp_temp_file != NULL)
+       {
+         int errno_save = errno;
+
+         unlink (cpp_temp_file);
+         errno = errno_save;
+         free (cpp_temp_file);
+       }
+    }
+  else
+    {
+      if (cpp_pipe != NULL)
+       pclose (cpp_pipe);
+    }
+
+  /* Since this is also run via xatexit, safeguard.  */
+  cpp_pipe = NULL;
+  cpp_temp_file = NULL;
 }
 
 /* Report an error while reading an rc file.  */
@@ -191,7 +539,7 @@ void
 rcparse_warning (msg)
      const char *msg;
 {
-  fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
+  fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
 }
 
 /* Die if we get an unexpected end of file.  */
@@ -200,7 +548,7 @@ static void
 unexpected_eof (msg)
      const char *msg;
 {
-  fatal ("%s: unexpected EOF", msg);
+  fatal (_("%s: unexpected EOF"), msg);
 }
 
 /* Read a 16 bit word from a file.  The data is assumed to be little
@@ -257,7 +605,7 @@ get_data (e, p, c, msg)
   if (got == c)
     return;
 
-  fatal ("%s: read of %lu returned %lu", msg, c, got);
+  fatal (_("%s: read of %lu returned %lu"), msg, c, got);
 }
 \f
 /* Define an accelerator resource.  */
@@ -270,7 +618,7 @@ define_accelerator (id, resinfo, data)
 {
   struct res_resource *r;
 
-  r = define_standard_resource (&resources, RT_ACCELERATORS, id,
+  r = define_standard_resource (&resources, RT_ACCELERATOR, id,
                                resinfo->language, 0);
   r->type = RES_TYPE_ACCELERATOR;
   r->u.acc = data;
@@ -299,7 +647,7 @@ define_bitmap (id, resinfo, filename)
   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,
+    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
           strerror (errno));
 
   data = (unsigned char *) res_alloc (s.st_size - BITMAP_SKIP);
@@ -352,7 +700,7 @@ define_cursor (id, resinfo, 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);
+    fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
 
   /* Read in the icon directory entries.  */
 
@@ -384,7 +732,7 @@ define_cursor (id, resinfo, filename)
       struct cursor *c;
 
       if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
-       fatal ("%s: fseek to %lu failed: %s", real_filename,
+       fatal (_("%s: fseek to %lu failed: %s"), real_filename,
               icondirs[i].offset, strerror (errno));
 
       data = (unsigned char *) res_alloc (icondirs[i].bytes);
@@ -470,8 +818,8 @@ define_dialog (id, resinfo, dialog)
    merely allocates and fills in a structure.  */
 
 struct dialog_control *
-define_control (text, id, x, y, width, height, class, style, exstyle)
-     const char *text;
+define_control (iid, id, x, y, width, height, class, style, exstyle)
+     struct res_id iid;
      unsigned long id;
      unsigned long x;
      unsigned long y;
@@ -494,19 +842,43 @@ define_control (text, id, x, y, width, height, class, style, exstyle)
   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;
-    }
+  n->text = iid;
   n->data = NULL;
   n->help = 0;
 
   return n;
 }
 
+struct dialog_control *
+define_icon_control (iid, id, x, y, style, exstyle, help, data, ex)
+     struct res_id iid;
+     unsigned long id;
+     unsigned long x;
+     unsigned long y;
+     unsigned long style;
+     unsigned long exstyle;
+     unsigned long help;
+     struct rcdata_item *data;
+     struct dialog_ex *ex;
+{
+  struct dialog_control *n;
+  struct res_id tid;
+
+  if (style == 0)
+    style = SS_ICON | WS_CHILD | WS_VISIBLE;
+  res_string_to_id (&tid, "");
+  n = define_control (tid, id, x, y, 0, 0, CTL_STATIC, style, exstyle);
+  n->text = iid;
+  if (help && !ex)
+    rcparse_warning (_("help ID requires DIALOGEX"));
+  if (data && !ex)
+    rcparse_warning (_("control data requires DIALOGEX"));
+  n->help = help;
+  n->data = data;
+
+  return n;
+}
+
 /* Define a font resource.  */
 
 void
@@ -530,7 +902,7 @@ define_font (id, resinfo, filename)
   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,
+    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
           strerror (errno));
 
   data = (unsigned char *) res_alloc (s.st_size);
@@ -643,7 +1015,7 @@ define_icon (id, resinfo, 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);
+    fatal (_("icon file `%s' does not contain icon data"), real_filename);
 
   /* Read in the icon directory entries.  */
 
@@ -674,7 +1046,7 @@ define_icon (id, resinfo, filename)
       struct res_id name;
 
       if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
-       fatal ("%s: fseek to %lu failed: %s", real_filename,
+       fatal (_("%s: fseek to %lu failed: %s"), real_filename,
               icondirs[i].offset, strerror (errno));
 
       data = (unsigned char *) res_alloc (icondirs[i].bytes);
@@ -803,7 +1175,7 @@ define_messagetable (id, resinfo, filename)
                        &real_filename);
 
   if (stat (real_filename, &s) < 0)
-    fatal ("stat failed on bitmap file `%s': %s", real_filename,
+    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
           strerror (errno));
 
   data = (unsigned char *) res_alloc (s.st_size);
@@ -890,7 +1262,7 @@ define_stringtable (resinfo, stringid, string)
   struct res_resource *r;
 
   id.named = 0;
-  id.u.id = stringid >> 4;
+  id.u.id = (stringid >> 4) + 1;
   r = define_standard_resource (&resources, RT_STRING, id,
                                resinfo->language, 1);
 
@@ -957,7 +1329,7 @@ define_user_file (id, type, resinfo, filename)
   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,
+    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
           strerror (errno));
 
   data = (unsigned char *) res_alloc (s.st_size);
@@ -1162,7 +1534,7 @@ write_rc_file (filename, resources)
     {
       e = fopen (filename, FOPEN_WT);
       if (e == NULL)
-       fatal ("can't open `%s' for output: %s", filename, strerror (errno));
+       fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
     }
 
   language = -1;
@@ -1210,7 +1582,7 @@ write_rc_directory (e, rd, type, name, language, level)
 
        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. */
+            we are going to use in the rc printout.  */
          name = &re->id;
          break;
 
@@ -1218,11 +1590,12 @@ write_rc_directory (e, rd, type, name, language, level)
          /* 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 != (unsigned long) (unsigned int) *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);
+                      re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
+                      (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
              *language = re->id.u.id;
            }
          break;
@@ -1289,7 +1662,7 @@ write_rc_subdir (e, re, type, name, language, level)
            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_ACCELERATOR: s = "accelerators"; break;
            case RT_RCDATA: s = "rcdata"; break;
            case RT_MESSAGETABLE: s = "messagetable"; break;
            case RT_GROUP_CURSOR: s = "group cursor"; break;
@@ -1327,7 +1700,7 @@ write_rc_subdir (e, re, type, name, language, level)
       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);
 }
@@ -1359,7 +1732,7 @@ write_rc_resource (e, type, name, res, language)
 
     case RES_TYPE_ACCELERATOR:
       s = "ACCELERATOR";
-      rt = RT_ACCELERATORS;
+      rt = RT_ACCELERATOR;
       break;
 
     case RES_TYPE_BITMAP:
@@ -1447,7 +1820,7 @@ write_rc_resource (e, type, name, res, language)
 
   if (rt != 0
       && type != NULL
-      && (type->named || type->u.id != rt))
+      && (type->named || type->u.id != (unsigned long) rt))
     {
       fprintf (e, "// Unexpected resource type mismatch: ");
       res_id_print (e, *type, 1);
@@ -1519,8 +1892,8 @@ write_rc_resource (e, type, name, res, language)
       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);
+                res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
+                (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
       if (res->res_info.characteristics != 0)
        fprintf (e, "%sCHARACTERISTICS %lu\n",
                 modifiers ? "// " : "",
@@ -1606,7 +1979,7 @@ write_rc_accelerators (e, accelerators)
       fprintf (e, "  ");
 
       if ((acc->key & 0x7f) == acc->key
-         && isprint ((unsigned char) acc->key)
+         && ISPRINT (acc->key)
          && (acc->flags & ACC_VIRTKEY) == 0)
        {
          fprintf (e, "\"%c\"", acc->key);
@@ -1682,36 +2055,45 @@ write_rc_dialog (e, dialog)
 {
   const struct dialog_control *control;
 
-  if (dialog->style != 0)
-    fprintf (e, "STYLE 0x%lx\n", dialog->style);
+  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)
+
+  if ((dialog->class.named && dialog->class.u.n.length > 0)
+      || dialog->class.u.id != 0)
     {
       fprintf (e, "CLASS ");
-      res_id_print (e, dialog->class, 0);
+      res_id_print (e, dialog->class, 1);
       fprintf (e, "\n");
     }
+
   if (dialog->caption != NULL)
     {
       fprintf (e, "CAPTION \"");
       unicode_print (e, dialog->caption, -1);
       fprintf (e, "\"\n");
     }
-  if (dialog->menu.named || dialog->menu.u.id != 0)
+
+  if ((dialog->menu.named && dialog->menu.u.n.length > 0)
+      || 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, \"", dialog->pointsize);
       unicode_print (e, dialog->font, -1);
       fprintf (e, "\"");
       if (dialog->ex != NULL
-         && (dialog->ex->weight != 0 || dialog->ex->italic != 0))
-       fprintf (e, ", %d, %d", dialog->ex->weight, dialog->ex->italic);
+         && (dialog->ex->weight != 0
+             || dialog->ex->italic != 0
+             || dialog->ex->charset != 1))
+       fprintf (e, ", %d, %d, %d",
+                dialog->ex->weight, dialog->ex->italic, dialog->ex->charset);
       fprintf (e, "\n");
     }
 
@@ -1780,12 +2162,13 @@ write_rc_dialog_control (e, control)
                || ci->style == (control->style & 0xff)))
          break;
     }
-
-  if (ci->name != NULL)
+  if (ci == NULL)
+    fprintf (e, "CONTROL");
+  else if (ci->name != NULL)
     fprintf (e, "%s", ci->name);
   else
     fprintf (e, "CONTROL");
-  
+
   if (control->text.named || control->text.u.id != 0)
     {
       fprintf (e, " ");
@@ -1795,9 +2178,13 @@ write_rc_dialog_control (e, control)
 
   fprintf (e, " %d, ", control->id);
 
-  if (ci->name == NULL)
+  if (ci == NULL)
     {
+      if (control->class.named)
+       fprintf (e, "\"");
       res_id_print (e, control->class, 0);
+      if (control->class.named)
+       fprintf (e, "\"");
       fprintf (e, ", 0x%lx, ", control->style);
     }
 
@@ -2006,7 +2393,7 @@ write_rc_rcdata (e, rcdata, ind)
            s = ri->u.string.s;
            for (i = 0; i < ri->u.string.length; i++)
              {
-               if (isprint (*s))
+               if (ISPRINT (*s))
                  putc (*s, e);
                else
                  fprintf (e, "\\%03o", *s);
@@ -2032,60 +2419,100 @@ write_rc_rcdata (e, rcdata, ind)
            for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
              {
                unsigned long l;
+               int j;
 
+               if (! first)
+                 indent (e, ind + 2);
                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, "%luL", l);
+               if (i + 4 < ri->u.buffer.length || ri->next != NULL)
+                 fprintf (e, ",");
+               for (j = 0; j < 4; ++j)
+                 if (! ISPRINT (ri->u.buffer.data[i + j])
+                     && ri->u.buffer.data[i + j] != 0)
+                   break;
+               if (j >= 4)
                  {
-                   fprintf (e, ",\n");
-                   indent (e, ind + 2);
+                   fprintf (e, "\t// ");
+                   for (j = 0; j < 4; ++j)
+                     {
+                       if (! ISPRINT (ri->u.buffer.data[i + j]))
+                         fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
+                       else
+                         {
+                           if (ri->u.buffer.data[i + j] == '\\')
+                             fprintf (e, "\\");
+                           fprintf (e, "%c", ri->u.buffer.data[i + j]);
+                         }
+                     }
                  }
-               fprintf (e, "%luL", l);
+               fprintf (e, "\n");
+               first = 0;
              }
 
            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
+               int s;
+               int j;
+
+               if (! first)
+                 indent (e, ind + 2);
+               s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
+               fprintf (e, "%d", s);
+               if (i + 2 < ri->u.buffer.length || ri->next != NULL)
+                 fprintf (e, ",");
+               for (j = 0; j < 2; ++j)
+                 if (! ISPRINT (ri->u.buffer.data[i + j])
+                     && ri->u.buffer.data[i + j] != 0)
+                   break;
+               if (j >= 2)
                  {
-                   fprintf (e, ",\n");
-                   indent (e, ind + 2);
+                   fprintf (e, "\t// ");
+                   for (j = 0; j < 2; ++j)
+                     {
+                       if (! ISPRINT (ri->u.buffer.data[i + j]))
+                         fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
+                       else
+                         {
+                           if (ri->u.buffer.data[i + j] == '\\')
+                             fprintf (e, "\\");
+                           fprintf (e, "%c", ri->u.buffer.data[i + j]);
+                         }
+                     }
                  }
-               fprintf (e, "%d", i);
+               fprintf (e, "\n");
                i += 2;
+               first = 0;
              }
 
            if (i < ri->u.buffer.length)
              {
-               if (first)
-                 first = 0;
-               else
-                 {
-                   fprintf (e, ",\n");
-                   indent (e, ind + 2);
-                 }
+               if (! first)
+                 indent (e, ind + 2);
                if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
-                   && isprint (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]);
+                 fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
+               if (ri->next != NULL)
+                 fprintf (e, ",");
+               fprintf (e, "\n");
+               first = 0;
              }
 
            break;
          }
        }
 
-      if (ri->next != NULL)
-       fprintf (e, ",");
-      fprintf (e, "\n");
+      if (ri->type != RCDATA_BUFFER)
+       {
+         if (ri->next != NULL)
+           fprintf (e, ",");
+         fprintf (e, "\n");
+       }
     }
 
   indent (e, ind);
@@ -2104,7 +2531,7 @@ write_rc_stringtable (e, name, stringtable)
   int i;
 
   if (name != NULL && ! name->named)
-    offset = name->u.id << 4;
+    offset = (name->u.id - 1) << 4;
   else
     {
       fprintf (e, "// %s string table name\n",