resrc.c revision 104834
138889Sjdp/* resrc.c -- read and write Windows rc files.
299461Sobrien   Copyright 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
338889Sjdp   Written by Ian Lance Taylor, Cygnus Support.
438889Sjdp
538889Sjdp   This file is part of GNU Binutils.
638889Sjdp
738889Sjdp   This program is free software; you can redistribute it and/or modify
838889Sjdp   it under the terms of the GNU General Public License as published by
938889Sjdp   the Free Software Foundation; either version 2 of the License, or
1038889Sjdp   (at your option) any later version.
1138889Sjdp
1238889Sjdp   This program is distributed in the hope that it will be useful,
1338889Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1438889Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1538889Sjdp   GNU General Public License for more details.
1638889Sjdp
1738889Sjdp   You should have received a copy of the GNU General Public License
1838889Sjdp   along with this program; if not, write to the Free Software
1938889Sjdp   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
2038889Sjdp   02111-1307, USA.  */
2138889Sjdp
2238889Sjdp/* This file contains functions that read and write Windows rc files.
2338889Sjdp   These are text files that represent resources.  */
2438889Sjdp
2538889Sjdp#include "bfd.h"
2638889Sjdp#include "bucomm.h"
2738889Sjdp#include "libiberty.h"
2889857Sobrien#include "safe-ctype.h"
2938889Sjdp#include "windres.h"
3038889Sjdp
3138889Sjdp#include <assert.h>
3260484Sobrien#include <errno.h>
3338889Sjdp#include <sys/stat.h>
3460484Sobrien#ifdef HAVE_UNISTD_H
3560484Sobrien#include <unistd.h>
3660484Sobrien#endif
3738889Sjdp
3860484Sobrien#ifdef HAVE_SYS_WAIT_H
3960484Sobrien#include <sys/wait.h>
4060484Sobrien#else /* ! HAVE_SYS_WAIT_H */
4160484Sobrien#if ! defined (_WIN32) || defined (__CYGWIN__)
4260484Sobrien#ifndef WIFEXITED
4360484Sobrien#define WIFEXITED(w)	(((w)&0377) == 0)
4460484Sobrien#endif
4560484Sobrien#ifndef WIFSIGNALED
4660484Sobrien#define WIFSIGNALED(w)	(((w)&0377) != 0177 && ((w)&~0377) == 0)
4760484Sobrien#endif
4860484Sobrien#ifndef WTERMSIG
4960484Sobrien#define WTERMSIG(w)	((w) & 0177)
5060484Sobrien#endif
5160484Sobrien#ifndef WEXITSTATUS
5260484Sobrien#define WEXITSTATUS(w)	(((w) >> 8) & 0377)
5360484Sobrien#endif
5460484Sobrien#else /* defined (_WIN32) && ! defined (__CYGWIN__) */
5560484Sobrien#ifndef WIFEXITED
5660484Sobrien#define WIFEXITED(w)	(((w) & 0xff) == 0)
5760484Sobrien#endif
5860484Sobrien#ifndef WIFSIGNALED
5960484Sobrien#define WIFSIGNALED(w)	(((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
6060484Sobrien#endif
6160484Sobrien#ifndef WTERMSIG
6260484Sobrien#define WTERMSIG(w)	((w) & 0x7f)
6360484Sobrien#endif
6460484Sobrien#ifndef WEXITSTATUS
6560484Sobrien#define WEXITSTATUS(w)	(((w) & 0xff00) >> 8)
6660484Sobrien#endif
6760484Sobrien#endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
6860484Sobrien#endif /* ! HAVE_SYS_WAIT_H */
6960484Sobrien
7060484Sobrien#ifndef STDOUT_FILENO
7160484Sobrien#define STDOUT_FILENO 1
7260484Sobrien#endif
73104834Sobrien
7460484Sobrien#if defined (_WIN32) && ! defined (__CYGWIN__)
7538889Sjdp#define popen _popen
7638889Sjdp#define pclose _pclose
7738889Sjdp#endif
7838889Sjdp
7938889Sjdp/* The default preprocessor.  */
8038889Sjdp
8177298Sobrien#define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
8238889Sjdp
8338889Sjdp/* We read the directory entries in a cursor or icon file into
8438889Sjdp   instances of this structure.  */
8538889Sjdp
8638889Sjdpstruct icondir
8738889Sjdp{
8838889Sjdp  /* Width of image.  */
8938889Sjdp  unsigned char width;
9038889Sjdp  /* Height of image.  */
9138889Sjdp  unsigned char height;
9238889Sjdp  /* Number of colors in image.  */
9338889Sjdp  unsigned char colorcount;
9438889Sjdp  union
9538889Sjdp  {
9638889Sjdp    struct
9738889Sjdp    {
9838889Sjdp      /* Color planes.  */
9938889Sjdp      unsigned short planes;
10038889Sjdp      /* Bits per pixel.  */
10138889Sjdp      unsigned short bits;
10238889Sjdp    } icon;
10338889Sjdp    struct
10438889Sjdp    {
10538889Sjdp      /* X coordinate of hotspot.  */
10638889Sjdp      unsigned short xhotspot;
10738889Sjdp      /* Y coordinate of hotspot.  */
10838889Sjdp      unsigned short yhotspot;
10938889Sjdp    } cursor;
11038889Sjdp  } u;
11138889Sjdp  /* Bytes in image.  */
11238889Sjdp  unsigned long bytes;
11338889Sjdp  /* File offset of image.  */
11438889Sjdp  unsigned long offset;
11538889Sjdp};
11638889Sjdp
11738889Sjdp/* The name of the rc file we are reading.  */
11838889Sjdp
11938889Sjdpchar *rc_filename;
12038889Sjdp
12138889Sjdp/* The line number in the rc file.  */
12238889Sjdp
12338889Sjdpint rc_lineno;
12438889Sjdp
12538889Sjdp/* The pipe we are reading from, so that we can close it if we exit.  */
12638889Sjdp
12738889Sjdpstatic FILE *cpp_pipe;
12838889Sjdp
12960484Sobrien/* The temporary file used if we're not using popen, so we can delete it
13060484Sobrien   if we exit.  */
13160484Sobrien
13260484Sobrienstatic char *cpp_temp_file;
13360484Sobrien
13499461Sobrien/* Input stream is either a file or a pipe.  */
13560484Sobrien
13660484Sobrienstatic enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
13760484Sobrien
13838889Sjdp/* As we read the rc file, we attach information to this structure.  */
13938889Sjdp
14038889Sjdpstatic struct res_directory *resources;
14138889Sjdp
14238889Sjdp/* The number of cursor resources we have written out.  */
14338889Sjdp
14438889Sjdpstatic int cursors;
14538889Sjdp
14638889Sjdp/* The number of font resources we have written out.  */
14738889Sjdp
14838889Sjdpstatic int fonts;
14938889Sjdp
15038889Sjdp/* Font directory information.  */
15138889Sjdp
15238889Sjdpstruct fontdir *fontdirs;
15338889Sjdp
15438889Sjdp/* Resource info to use for fontdirs.  */
15538889Sjdp
15638889Sjdpstruct res_res_info fontdirs_resinfo;
15738889Sjdp
15838889Sjdp/* The number of icon resources we have written out.  */
15938889Sjdp
16038889Sjdpstatic int icons;
16138889Sjdp
16238889Sjdp/* Local functions.  */
16338889Sjdp
16460484Sobrienstatic int run_cmd PARAMS ((char *, const char *));
16560484Sobrienstatic FILE *open_input_stream PARAMS ((char *));
16660484Sobrienstatic FILE *look_for_default PARAMS ((char *, const char *, int,
16760484Sobrien				       const char *, const char *));
16860484Sobrienstatic void close_input_stream PARAMS ((void));
16938889Sjdpstatic void unexpected_eof PARAMS ((const char *));
17038889Sjdpstatic int get_word PARAMS ((FILE *, const char *));
17138889Sjdpstatic unsigned long get_long PARAMS ((FILE *, const char *));
17238889Sjdpstatic void get_data
17338889Sjdp  PARAMS ((FILE *, unsigned char *, unsigned long, const char *));
17438889Sjdpstatic void define_fontdirs PARAMS ((void));
17538889Sjdp
17699461Sobrien/* Run `cmd' and redirect the output to `redir'.  */
17760484Sobrien
17860484Sobrienstatic int
17960484Sobrienrun_cmd (cmd, redir)
18060484Sobrien     char *cmd;
18160484Sobrien     const char *redir;
18260484Sobrien{
18360484Sobrien  char *s;
18460484Sobrien  int pid, wait_status, retcode;
18560484Sobrien  int i;
18660484Sobrien  const char **argv;
18760484Sobrien  char *errmsg_fmt, *errmsg_arg;
18860484Sobrien  char *temp_base = choose_temp_base ();
18960484Sobrien  int in_quote;
19060484Sobrien  char sep;
19160484Sobrien  int redir_handle = -1;
19260484Sobrien  int stdout_save = -1;
19360484Sobrien
19460484Sobrien  /* Count the args.  */
19560484Sobrien  i = 0;
196104834Sobrien
19760484Sobrien  for (s = cmd; *s; s++)
19860484Sobrien    if (*s == ' ')
19960484Sobrien      i++;
200104834Sobrien
20160484Sobrien  i++;
20260484Sobrien  argv = alloca (sizeof (char *) * (i + 3));
20360484Sobrien  i = 0;
20460484Sobrien  s = cmd;
205104834Sobrien
20660484Sobrien  while (1)
20760484Sobrien    {
20860484Sobrien      while (*s == ' ' && *s != 0)
20960484Sobrien	s++;
210104834Sobrien
21160484Sobrien      if (*s == 0)
21260484Sobrien	break;
213104834Sobrien
21460484Sobrien      in_quote = (*s == '\'' || *s == '"');
21560484Sobrien      sep = (in_quote) ? *s++ : ' ';
21660484Sobrien      argv[i++] = s;
217104834Sobrien
21860484Sobrien      while (*s != sep && *s != 0)
21960484Sobrien	s++;
220104834Sobrien
22160484Sobrien      if (*s == 0)
22260484Sobrien	break;
223104834Sobrien
22460484Sobrien      *s++ = 0;
225104834Sobrien
22660484Sobrien      if (in_quote)
227104834Sobrien	s++;
22860484Sobrien    }
22960484Sobrien  argv[i++] = NULL;
23060484Sobrien
23160484Sobrien  /* Setup the redirection.  We can't use the usual fork/exec and redirect
23260484Sobrien     since we may be running on non-POSIX Windows host.  */
23360484Sobrien
23460484Sobrien  fflush (stdout);
23560484Sobrien  fflush (stderr);
23660484Sobrien
23760484Sobrien  /* Open temporary output file.  */
23860484Sobrien  redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
23960484Sobrien  if (redir_handle == -1)
240104834Sobrien    fatal (_("can't open temporary file `%s': %s"), redir,
241104834Sobrien	   strerror (errno));
24260484Sobrien
24360484Sobrien  /* Duplicate the stdout file handle so it can be restored later.  */
24460484Sobrien  stdout_save = dup (STDOUT_FILENO);
24560484Sobrien  if (stdout_save == -1)
24660484Sobrien    fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
24760484Sobrien
24860484Sobrien  /* Redirect stdout to our output file.  */
24960484Sobrien  dup2 (redir_handle, STDOUT_FILENO);
25060484Sobrien
25160484Sobrien  pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
25260484Sobrien		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
25360484Sobrien
25460484Sobrien  /* Restore stdout to its previous setting.  */
25560484Sobrien  dup2 (stdout_save, STDOUT_FILENO);
25660484Sobrien
25760484Sobrien  /* Close reponse file.  */
25860484Sobrien  close (redir_handle);
25960484Sobrien
26060484Sobrien  if (pid == -1)
26160484Sobrien    {
26260484Sobrien      fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
26360484Sobrien      return 1;
26460484Sobrien    }
26560484Sobrien
26660484Sobrien  retcode = 0;
26760484Sobrien  pid = pwait (pid, &wait_status, 0);
268104834Sobrien
26960484Sobrien  if (pid == -1)
27060484Sobrien    {
27160484Sobrien      fatal (_("wait: %s"), strerror (errno));
27260484Sobrien      retcode = 1;
27360484Sobrien    }
27460484Sobrien  else if (WIFSIGNALED (wait_status))
27560484Sobrien    {
27660484Sobrien      fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
27760484Sobrien      retcode = 1;
27860484Sobrien    }
27960484Sobrien  else if (WIFEXITED (wait_status))
28060484Sobrien    {
28160484Sobrien      if (WEXITSTATUS (wait_status) != 0)
28260484Sobrien	{
283104834Sobrien	  fatal (_("%s exited with status %d"), cmd,
28460484Sobrien	         WEXITSTATUS (wait_status));
28560484Sobrien	  retcode = 1;
28660484Sobrien	}
28760484Sobrien    }
28860484Sobrien  else
28960484Sobrien    retcode = 1;
290104834Sobrien
29160484Sobrien  return retcode;
29260484Sobrien}
29360484Sobrien
29460484Sobrienstatic FILE *
29560484Sobrienopen_input_stream (cmd)
29660484Sobrien     char *cmd;
29760484Sobrien{
29860484Sobrien  if (istream_type == ISTREAM_FILE)
29960484Sobrien    {
30060484Sobrien      char *fileprefix;
30160484Sobrien
30260484Sobrien      fileprefix = choose_temp_base ();
30360484Sobrien      cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
30460484Sobrien      sprintf (cpp_temp_file, "%s.irc", fileprefix);
30560484Sobrien      free (fileprefix);
30660484Sobrien
30760484Sobrien      if (run_cmd (cmd, cpp_temp_file))
30860484Sobrien	fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
30960484Sobrien
31060484Sobrien      cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
31160484Sobrien      if (cpp_pipe == NULL)
312104834Sobrien	fatal (_("can't open temporary file `%s': %s"),
31360484Sobrien	       cpp_temp_file, strerror (errno));
314104834Sobrien
31560484Sobrien      if (verbose)
316104834Sobrien	fprintf (stderr,
31760484Sobrien	         _("Using temporary file `%s' to read preprocessor output\n"),
31860484Sobrien		 cpp_temp_file);
31960484Sobrien    }
32060484Sobrien  else
32160484Sobrien    {
32260484Sobrien      cpp_pipe = popen (cmd, FOPEN_RT);
32360484Sobrien      if (cpp_pipe == NULL)
324104834Sobrien	fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
32560484Sobrien      if (verbose)
32660484Sobrien	fprintf (stderr, _("Using popen to read preprocessor output\n"));
32760484Sobrien    }
32860484Sobrien
32960484Sobrien  xatexit (close_input_stream);
33060484Sobrien  return cpp_pipe;
33160484Sobrien}
33260484Sobrien
33360484Sobrien/* look for the preprocessor program */
33460484Sobrien
33560484Sobrienstatic FILE *
33660484Sobrienlook_for_default (cmd, prefix, end_prefix, preprocargs, filename)
33760484Sobrien     char *cmd;
33860484Sobrien     const char *prefix;
33960484Sobrien     int end_prefix;
34060484Sobrien     const char *preprocargs;
34160484Sobrien     const char *filename;
34260484Sobrien{
34360484Sobrien  char *space;
34460484Sobrien  int found;
34560484Sobrien  struct stat s;
34660484Sobrien
34760484Sobrien  strcpy (cmd, prefix);
34860484Sobrien
34960484Sobrien  sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
35060484Sobrien  space = strchr (cmd + end_prefix, ' ');
35160484Sobrien  if (space)
35260484Sobrien    *space = 0;
35360484Sobrien
35460484Sobrien  if (
35560484Sobrien#if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
35660484Sobrien      strchr (cmd, '\\') ||
35760484Sobrien#endif
35860484Sobrien      strchr (cmd, '/'))
35960484Sobrien    {
36060484Sobrien      found = (stat (cmd, &s) == 0
36160484Sobrien#ifdef HAVE_EXECUTABLE_SUFFIX
36260484Sobrien	       || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
36360484Sobrien#endif
36460484Sobrien	       );
36560484Sobrien
36660484Sobrien      if (! found)
36760484Sobrien	{
36860484Sobrien	  if (verbose)
36960484Sobrien	    fprintf (stderr, _("Tried `%s'\n"), cmd);
37060484Sobrien	  return NULL;
37160484Sobrien	}
37260484Sobrien    }
37360484Sobrien
37460484Sobrien  strcpy (cmd, prefix);
37560484Sobrien
37660484Sobrien  sprintf (cmd + end_prefix, "%s %s %s",
37760484Sobrien	   DEFAULT_PREPROCESSOR, preprocargs, filename);
37860484Sobrien
37960484Sobrien  if (verbose)
38060484Sobrien    fprintf (stderr, _("Using `%s'\n"), cmd);
38160484Sobrien
38260484Sobrien  cpp_pipe = open_input_stream (cmd);
38360484Sobrien  return cpp_pipe;
38460484Sobrien}
38560484Sobrien
38638889Sjdp/* Read an rc file.  */
38738889Sjdp
38838889Sjdpstruct res_directory *
38960484Sobrienread_rc_file (filename, preprocessor, preprocargs, language, use_temp_file)
39038889Sjdp     const char *filename;
39138889Sjdp     const char *preprocessor;
39238889Sjdp     const char *preprocargs;
39338889Sjdp     int language;
39460484Sobrien     int use_temp_file;
39538889Sjdp{
39638889Sjdp  char *cmd;
39738889Sjdp
39860484Sobrien  istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
39938889Sjdp
40038889Sjdp  if (preprocargs == NULL)
40138889Sjdp    preprocargs = "";
40238889Sjdp  if (filename == NULL)
40338889Sjdp    filename = "-";
40438889Sjdp
40560484Sobrien  if (preprocessor)
40660484Sobrien    {
40760484Sobrien      cmd = xmalloc (strlen (preprocessor)
40860484Sobrien		     + strlen (preprocargs)
40960484Sobrien		     + strlen (filename)
41060484Sobrien		     + 10);
41160484Sobrien      sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
41238889Sjdp
41360484Sobrien      cpp_pipe = open_input_stream (cmd);
41460484Sobrien    }
41560484Sobrien  else
41660484Sobrien    {
41760484Sobrien      char *dash, *slash, *cp;
41860484Sobrien
41960484Sobrien      preprocessor = DEFAULT_PREPROCESSOR;
42060484Sobrien
42160484Sobrien      cmd = xmalloc (strlen (program_name)
42260484Sobrien		     + strlen (preprocessor)
42360484Sobrien		     + strlen (preprocargs)
42460484Sobrien		     + strlen (filename)
42560484Sobrien#ifdef HAVE_EXECUTABLE_SUFFIX
42660484Sobrien		     + strlen (EXECUTABLE_SUFFIX)
42760484Sobrien#endif
42860484Sobrien		     + 10);
42960484Sobrien
43060484Sobrien
43160484Sobrien      dash = slash = 0;
43260484Sobrien      for (cp = program_name; *cp; cp++)
43360484Sobrien	{
43460484Sobrien	  if (*cp == '-')
43560484Sobrien	    dash = cp;
43660484Sobrien	  if (
43760484Sobrien#if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
43860484Sobrien	      *cp == ':' || *cp == '\\' ||
43960484Sobrien#endif
44060484Sobrien	      *cp == '/')
44160484Sobrien	    {
44260484Sobrien	      slash = cp;
44360484Sobrien	      dash = 0;
44460484Sobrien	    }
44560484Sobrien	}
44660484Sobrien
44760484Sobrien      cpp_pipe = 0;
44860484Sobrien
44960484Sobrien      if (dash)
45060484Sobrien	{
45160484Sobrien	  /* First, try looking for a prefixed gcc in the windres
45260484Sobrien	     directory, with the same prefix as windres */
45360484Sobrien
45460484Sobrien	  cpp_pipe = look_for_default (cmd, program_name, dash-program_name+1,
45560484Sobrien				       preprocargs, filename);
45660484Sobrien	}
45760484Sobrien
45860484Sobrien      if (slash && !cpp_pipe)
45960484Sobrien	{
46060484Sobrien	  /* Next, try looking for a gcc in the same directory as
46160484Sobrien             that windres */
46260484Sobrien
46360484Sobrien	  cpp_pipe = look_for_default (cmd, program_name, slash-program_name+1,
46460484Sobrien				       preprocargs, filename);
46560484Sobrien	}
46660484Sobrien
46760484Sobrien      if (!cpp_pipe)
46860484Sobrien	{
46960484Sobrien	  /* Sigh, try the default */
47060484Sobrien
47160484Sobrien	  cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
47260484Sobrien	}
47360484Sobrien
47460484Sobrien    }
475104834Sobrien
47638889Sjdp  free (cmd);
47738889Sjdp
47838889Sjdp  rc_filename = xstrdup (filename);
47938889Sjdp  rc_lineno = 1;
48038889Sjdp  if (language != -1)
48138889Sjdp    rcparse_set_language (language);
48238889Sjdp  yyin = cpp_pipe;
48338889Sjdp  yyparse ();
48499461Sobrien  rcparse_discard_strings ();
48538889Sjdp
48660484Sobrien  close_input_stream ();
487104834Sobrien
48838889Sjdp  if (fontdirs != NULL)
48938889Sjdp    define_fontdirs ();
49038889Sjdp
49138889Sjdp  free (rc_filename);
49238889Sjdp  rc_filename = NULL;
49338889Sjdp
49438889Sjdp  return resources;
49538889Sjdp}
49638889Sjdp
49760484Sobrien/* Close the input stream if it is open.  */
49838889Sjdp
49960484Sobrienstatic void
50060484Sobrienclose_input_stream ()
50138889Sjdp{
50260484Sobrien  if (istream_type == ISTREAM_FILE)
50360484Sobrien    {
50460484Sobrien      if (cpp_pipe != NULL)
50560484Sobrien	fclose (cpp_pipe);
50660484Sobrien
50760484Sobrien      if (cpp_temp_file != NULL)
50860484Sobrien	{
50960484Sobrien	  int errno_save = errno;
510104834Sobrien
51160484Sobrien	  unlink (cpp_temp_file);
51260484Sobrien	  errno = errno_save;
51360484Sobrien	  free (cpp_temp_file);
51460484Sobrien	}
51560484Sobrien    }
51660484Sobrien  else
51760484Sobrien    {
51860484Sobrien      if (cpp_pipe != NULL)
51960484Sobrien	pclose (cpp_pipe);
52060484Sobrien    }
52160484Sobrien
52299461Sobrien  /* Since this is also run via xatexit, safeguard.  */
52360484Sobrien  cpp_pipe = NULL;
52460484Sobrien  cpp_temp_file = NULL;
52538889Sjdp}
52638889Sjdp
52738889Sjdp/* Report an error while reading an rc file.  */
52838889Sjdp
52938889Sjdpvoid
53038889Sjdpyyerror (msg)
53138889Sjdp     const char *msg;
53238889Sjdp{
53338889Sjdp  fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
53438889Sjdp}
53538889Sjdp
53638889Sjdp/* Issue a warning while reading an rc file.  */
53738889Sjdp
53838889Sjdpvoid
53938889Sjdprcparse_warning (msg)
54038889Sjdp     const char *msg;
54138889Sjdp{
54260484Sobrien  fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
54338889Sjdp}
54438889Sjdp
54538889Sjdp/* Die if we get an unexpected end of file.  */
54638889Sjdp
54738889Sjdpstatic void
54838889Sjdpunexpected_eof (msg)
54938889Sjdp     const char *msg;
55038889Sjdp{
55160484Sobrien  fatal (_("%s: unexpected EOF"), msg);
55238889Sjdp}
55338889Sjdp
55438889Sjdp/* Read a 16 bit word from a file.  The data is assumed to be little
55538889Sjdp   endian.  */
55638889Sjdp
55738889Sjdpstatic int
55838889Sjdpget_word (e, msg)
55938889Sjdp     FILE *e;
56038889Sjdp     const char *msg;
56138889Sjdp{
56238889Sjdp  int b1, b2;
56338889Sjdp
56438889Sjdp  b1 = getc (e);
56538889Sjdp  b2 = getc (e);
56638889Sjdp  if (feof (e))
56738889Sjdp    unexpected_eof (msg);
56838889Sjdp  return ((b2 & 0xff) << 8) | (b1 & 0xff);
56938889Sjdp}
57038889Sjdp
57138889Sjdp/* Read a 32 bit word from a file.  The data is assumed to be little
57238889Sjdp   endian.  */
57338889Sjdp
57438889Sjdpstatic unsigned long
57538889Sjdpget_long (e, msg)
57638889Sjdp     FILE *e;
57738889Sjdp     const char *msg;
57838889Sjdp{
57938889Sjdp  int b1, b2, b3, b4;
58038889Sjdp
58138889Sjdp  b1 = getc (e);
58238889Sjdp  b2 = getc (e);
58338889Sjdp  b3 = getc (e);
58438889Sjdp  b4 = getc (e);
58538889Sjdp  if (feof (e))
58638889Sjdp    unexpected_eof (msg);
58738889Sjdp  return (((((((b4 & 0xff) << 8)
58838889Sjdp	      | (b3 & 0xff)) << 8)
58938889Sjdp	    | (b2 & 0xff)) << 8)
59038889Sjdp	  | (b1 & 0xff));
59138889Sjdp}
59238889Sjdp
59338889Sjdp/* Read data from a file.  This is a wrapper to do error checking.  */
59438889Sjdp
59538889Sjdpstatic void
59638889Sjdpget_data (e, p, c, msg)
59738889Sjdp     FILE *e;
59838889Sjdp     unsigned char *p;
59938889Sjdp     unsigned long c;
60038889Sjdp     const char *msg;
60138889Sjdp{
60238889Sjdp  unsigned long got;
60338889Sjdp
60438889Sjdp  got = fread (p, 1, c, e);
60538889Sjdp  if (got == c)
60638889Sjdp    return;
60738889Sjdp
60860484Sobrien  fatal (_("%s: read of %lu returned %lu"), msg, c, got);
60938889Sjdp}
61038889Sjdp
61138889Sjdp/* Define an accelerator resource.  */
61238889Sjdp
61338889Sjdpvoid
61438889Sjdpdefine_accelerator (id, resinfo, data)
61538889Sjdp     struct res_id id;
61638889Sjdp     const struct res_res_info *resinfo;
61738889Sjdp     struct accelerator *data;
61838889Sjdp{
61938889Sjdp  struct res_resource *r;
62038889Sjdp
62160484Sobrien  r = define_standard_resource (&resources, RT_ACCELERATOR, id,
62238889Sjdp				resinfo->language, 0);
62338889Sjdp  r->type = RES_TYPE_ACCELERATOR;
62438889Sjdp  r->u.acc = data;
62538889Sjdp  r->res_info = *resinfo;
62638889Sjdp}
62738889Sjdp
62838889Sjdp/* Define a bitmap resource.  Bitmap data is stored in a file.  The
62938889Sjdp   first 14 bytes of the file are a standard header, which is not
63038889Sjdp   included in the resource data.  */
63138889Sjdp
63238889Sjdp#define BITMAP_SKIP (14)
63338889Sjdp
63438889Sjdpvoid
63538889Sjdpdefine_bitmap (id, resinfo, filename)
63638889Sjdp     struct res_id id;
63738889Sjdp     const struct res_res_info *resinfo;
63838889Sjdp     const char *filename;
63938889Sjdp{
64038889Sjdp  FILE *e;
64138889Sjdp  char *real_filename;
64238889Sjdp  struct stat s;
64338889Sjdp  unsigned char *data;
64438889Sjdp  int i;
64538889Sjdp  struct res_resource *r;
64638889Sjdp
64738889Sjdp  e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
64838889Sjdp
64938889Sjdp  if (stat (real_filename, &s) < 0)
65060484Sobrien    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
65138889Sjdp	   strerror (errno));
65238889Sjdp
65338889Sjdp  data = (unsigned char *) res_alloc (s.st_size - BITMAP_SKIP);
65438889Sjdp
65538889Sjdp  for (i = 0; i < BITMAP_SKIP; i++)
65638889Sjdp    getc (e);
65738889Sjdp
65838889Sjdp  get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
65938889Sjdp
66038889Sjdp  fclose (e);
66138889Sjdp  free (real_filename);
66238889Sjdp
66338889Sjdp  r = define_standard_resource (&resources, RT_BITMAP, id,
66438889Sjdp				resinfo->language, 0);
66538889Sjdp
66638889Sjdp  r->type = RES_TYPE_BITMAP;
66738889Sjdp  r->u.data.length = s.st_size - BITMAP_SKIP;
66838889Sjdp  r->u.data.data = data;
66938889Sjdp  r->res_info = *resinfo;
67038889Sjdp}
67138889Sjdp
67238889Sjdp/* Define a cursor resource.  A cursor file may contain a set of
67338889Sjdp   bitmaps, each representing the same cursor at various different
67438889Sjdp   resolutions.  They each get written out with a different ID.  The
67538889Sjdp   real cursor resource is then a group resource which can be used to
67638889Sjdp   select one of the actual cursors.  */
67738889Sjdp
67838889Sjdpvoid
67938889Sjdpdefine_cursor (id, resinfo, filename)
68038889Sjdp     struct res_id id;
68138889Sjdp     const struct res_res_info *resinfo;
68238889Sjdp     const char *filename;
68338889Sjdp{
68438889Sjdp  FILE *e;
68538889Sjdp  char *real_filename;
68638889Sjdp  int type, count, i;
68738889Sjdp  struct icondir *icondirs;
68838889Sjdp  int first_cursor;
68938889Sjdp  struct res_resource *r;
69038889Sjdp  struct group_cursor *first, **pp;
69138889Sjdp
69238889Sjdp  e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
69338889Sjdp
69438889Sjdp  /* A cursor file is basically an icon file.  The start of the file
69538889Sjdp     is a three word structure.  The first word is ignored.  The
69638889Sjdp     second word is the type of data.  The third word is the number of
69738889Sjdp     entries.  */
69838889Sjdp
69938889Sjdp  get_word (e, real_filename);
70038889Sjdp  type = get_word (e, real_filename);
70138889Sjdp  count = get_word (e, real_filename);
70238889Sjdp  if (type != 2)
70360484Sobrien    fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
70438889Sjdp
70538889Sjdp  /* Read in the icon directory entries.  */
70638889Sjdp
70738889Sjdp  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
70838889Sjdp
70938889Sjdp  for (i = 0; i < count; i++)
71038889Sjdp    {
71138889Sjdp      icondirs[i].width = getc (e);
71238889Sjdp      icondirs[i].height = getc (e);
71338889Sjdp      icondirs[i].colorcount = getc (e);
71438889Sjdp      getc (e);
71538889Sjdp      icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
71638889Sjdp      icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
71738889Sjdp      icondirs[i].bytes = get_long (e, real_filename);
71838889Sjdp      icondirs[i].offset = get_long (e, real_filename);
71938889Sjdp
72038889Sjdp      if (feof (e))
72138889Sjdp	unexpected_eof (real_filename);
72238889Sjdp    }
72338889Sjdp
72438889Sjdp  /* Define each cursor as a unique resource.  */
72538889Sjdp
72638889Sjdp  first_cursor = cursors;
72738889Sjdp
72838889Sjdp  for (i = 0; i < count; i++)
72938889Sjdp    {
73038889Sjdp      unsigned char *data;
73138889Sjdp      struct res_id name;
73238889Sjdp      struct cursor *c;
73338889Sjdp
73438889Sjdp      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
73560484Sobrien	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
73638889Sjdp	       icondirs[i].offset, strerror (errno));
73738889Sjdp
73838889Sjdp      data = (unsigned char *) res_alloc (icondirs[i].bytes);
73938889Sjdp
74038889Sjdp      get_data (e, data, icondirs[i].bytes, real_filename);
74138889Sjdp
74238889Sjdp      c = (struct cursor *) res_alloc (sizeof *c);
74338889Sjdp      c->xhotspot = icondirs[i].u.cursor.xhotspot;
74438889Sjdp      c->yhotspot = icondirs[i].u.cursor.yhotspot;
74538889Sjdp      c->length = icondirs[i].bytes;
74638889Sjdp      c->data = data;
74738889Sjdp
74838889Sjdp      ++cursors;
74938889Sjdp
75038889Sjdp      name.named = 0;
75138889Sjdp      name.u.id = cursors;
75238889Sjdp
75338889Sjdp      r = define_standard_resource (&resources, RT_CURSOR, name,
75438889Sjdp				    resinfo->language, 0);
75538889Sjdp      r->type = RES_TYPE_CURSOR;
75638889Sjdp      r->u.cursor = c;
75738889Sjdp      r->res_info = *resinfo;
75838889Sjdp    }
75938889Sjdp
76038889Sjdp  fclose (e);
76138889Sjdp  free (real_filename);
76238889Sjdp
76338889Sjdp  /* Define a cursor group resource.  */
76438889Sjdp
76538889Sjdp  first = NULL;
76638889Sjdp  pp = &first;
76738889Sjdp  for (i = 0; i < count; i++)
76838889Sjdp    {
76938889Sjdp      struct group_cursor *cg;
77038889Sjdp
77138889Sjdp      cg = (struct group_cursor *) res_alloc (sizeof *cg);
77238889Sjdp      cg->next = NULL;
77338889Sjdp      cg->width = icondirs[i].width;
77438889Sjdp      cg->height = 2 * icondirs[i].height;
77538889Sjdp
77638889Sjdp      /* FIXME: What should these be set to?  */
77738889Sjdp      cg->planes = 1;
77838889Sjdp      cg->bits = 1;
77938889Sjdp
78038889Sjdp      cg->bytes = icondirs[i].bytes + 4;
78138889Sjdp      cg->index = first_cursor + i + 1;
78238889Sjdp
78338889Sjdp      *pp = cg;
78438889Sjdp      pp = &(*pp)->next;
78538889Sjdp    }
78638889Sjdp
78738889Sjdp  free (icondirs);
78838889Sjdp
78938889Sjdp  r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
79038889Sjdp				resinfo->language, 0);
79138889Sjdp  r->type = RES_TYPE_GROUP_CURSOR;
79238889Sjdp  r->u.group_cursor = first;
79338889Sjdp  r->res_info = *resinfo;
79438889Sjdp}
79538889Sjdp
79638889Sjdp/* Define a dialog resource.  */
79738889Sjdp
79838889Sjdpvoid
79938889Sjdpdefine_dialog (id, resinfo, dialog)
80038889Sjdp     struct res_id id;
80138889Sjdp     const struct res_res_info *resinfo;
80238889Sjdp     const struct dialog *dialog;
80338889Sjdp{
80438889Sjdp  struct dialog *copy;
80538889Sjdp  struct res_resource *r;
80638889Sjdp
80738889Sjdp  copy = (struct dialog *) res_alloc (sizeof *copy);
80838889Sjdp  *copy = *dialog;
80938889Sjdp
81038889Sjdp  r = define_standard_resource (&resources, RT_DIALOG, id,
81138889Sjdp				resinfo->language, 0);
81238889Sjdp  r->type = RES_TYPE_DIALOG;
81338889Sjdp  r->u.dialog = copy;
81438889Sjdp  r->res_info = *resinfo;
81538889Sjdp}
81638889Sjdp
81738889Sjdp/* Define a dialog control.  This does not define a resource, but
81838889Sjdp   merely allocates and fills in a structure.  */
81938889Sjdp
82038889Sjdpstruct dialog_control *
82138889Sjdpdefine_control (text, id, x, y, width, height, class, style, exstyle)
82238889Sjdp     const char *text;
82338889Sjdp     unsigned long id;
82438889Sjdp     unsigned long x;
82538889Sjdp     unsigned long y;
82638889Sjdp     unsigned long width;
82738889Sjdp     unsigned long height;
82838889Sjdp     unsigned long class;
82938889Sjdp     unsigned long style;
83038889Sjdp     unsigned long exstyle;
83138889Sjdp{
83238889Sjdp  struct dialog_control *n;
83338889Sjdp
83438889Sjdp  n = (struct dialog_control *) res_alloc (sizeof *n);
83538889Sjdp  n->next = NULL;
83638889Sjdp  n->id = id;
83738889Sjdp  n->style = style;
83838889Sjdp  n->exstyle = exstyle;
83938889Sjdp  n->x = x;
84038889Sjdp  n->y = y;
84138889Sjdp  n->width = width;
84238889Sjdp  n->height = height;
84338889Sjdp  n->class.named = 0;
84438889Sjdp  n->class.u.id = class;
84577298Sobrien  if (text == NULL)
84677298Sobrien    text = "";
84777298Sobrien  res_string_to_id (&n->text, text);
84838889Sjdp  n->data = NULL;
84938889Sjdp  n->help = 0;
85038889Sjdp
85138889Sjdp  return n;
85238889Sjdp}
85338889Sjdp
85477298Sobrienstruct dialog_control *
85577298Sobriendefine_icon_control (iid, id, x, y, style, exstyle, help, data, ex)
85677298Sobrien     struct res_id iid;
85777298Sobrien     unsigned long id;
85877298Sobrien     unsigned long x;
85977298Sobrien     unsigned long y;
86077298Sobrien     unsigned long style;
86177298Sobrien     unsigned long exstyle;
86277298Sobrien     unsigned long help;
86377298Sobrien     struct rcdata_item *data;
86477298Sobrien     struct dialog_ex *ex;
86577298Sobrien{
86677298Sobrien  struct dialog_control *n;
86777298Sobrien  if (style == 0)
86877298Sobrien    style = SS_ICON | WS_CHILD | WS_VISIBLE;
86977298Sobrien  n = define_control (0, id, x, y, 0, 0, CTL_STATIC, style, exstyle);
87077298Sobrien  n->text = iid;
87177298Sobrien  if (help && !ex)
87277298Sobrien    rcparse_warning (_("help ID requires DIALOGEX"));
87377298Sobrien  if (data && !ex)
87477298Sobrien    rcparse_warning (_("control data requires DIALOGEX"));
87577298Sobrien  n->help = help;
87677298Sobrien  n->data = data;
87777298Sobrien
87877298Sobrien  return n;
87977298Sobrien}
88077298Sobrien
88138889Sjdp/* Define a font resource.  */
88238889Sjdp
88338889Sjdpvoid
88438889Sjdpdefine_font (id, resinfo, filename)
88538889Sjdp     struct res_id id;
88638889Sjdp     const struct res_res_info *resinfo;
88738889Sjdp     const char *filename;
88838889Sjdp{
88938889Sjdp  FILE *e;
89038889Sjdp  char *real_filename;
89138889Sjdp  struct stat s;
89238889Sjdp  unsigned char *data;
89338889Sjdp  struct res_resource *r;
89438889Sjdp  long offset;
89538889Sjdp  long fontdatalength;
89638889Sjdp  unsigned char *fontdata;
89738889Sjdp  struct fontdir *fd;
89838889Sjdp  const char *device, *face;
89938889Sjdp  struct fontdir **pp;
90038889Sjdp
90138889Sjdp  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
90238889Sjdp
90338889Sjdp  if (stat (real_filename, &s) < 0)
90460484Sobrien    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
90538889Sjdp	   strerror (errno));
90638889Sjdp
90738889Sjdp  data = (unsigned char *) res_alloc (s.st_size);
90838889Sjdp
90938889Sjdp  get_data (e, data, s.st_size, real_filename);
91038889Sjdp
91138889Sjdp  fclose (e);
91238889Sjdp  free (real_filename);
91338889Sjdp
91438889Sjdp  r = define_standard_resource (&resources, RT_FONT, id,
91538889Sjdp				resinfo->language, 0);
91638889Sjdp
91738889Sjdp  r->type = RES_TYPE_FONT;
91838889Sjdp  r->u.data.length = s.st_size;
91938889Sjdp  r->u.data.data = data;
92038889Sjdp  r->res_info = *resinfo;
92138889Sjdp
92238889Sjdp  /* For each font resource, we must add an entry in the FONTDIR
92338889Sjdp     resource.  The FONTDIR resource includes some strings in the font
92438889Sjdp     file.  To find them, we have to do some magic on the data we have
92538889Sjdp     read.  */
92638889Sjdp
92738889Sjdp  offset = ((((((data[47] << 8)
92838889Sjdp		| data[46]) << 8)
92938889Sjdp	      | data[45]) << 8)
93038889Sjdp	    | data[44]);
93138889Sjdp  if (offset > 0 && offset < s.st_size)
93238889Sjdp    device = (char *) data + offset;
93338889Sjdp  else
93438889Sjdp    device = "";
93538889Sjdp
93638889Sjdp  offset = ((((((data[51] << 8)
93738889Sjdp		| data[50]) << 8)
93838889Sjdp	      | data[49]) << 8)
93938889Sjdp	    | data[48]);
94038889Sjdp  if (offset > 0 && offset < s.st_size)
94138889Sjdp    face = (char *) data + offset;
94238889Sjdp  else
94338889Sjdp    face = "";
94438889Sjdp
94538889Sjdp  ++fonts;
94638889Sjdp
94738889Sjdp  fontdatalength = 58 + strlen (device) + strlen (face);
94838889Sjdp  fontdata = (unsigned char *) res_alloc (fontdatalength);
94938889Sjdp  memcpy (fontdata, data, 56);
95038889Sjdp  strcpy ((char *) fontdata + 56, device);
95138889Sjdp  strcpy ((char *) fontdata + 57 + strlen (device), face);
95238889Sjdp
95338889Sjdp  fd = (struct fontdir *) res_alloc (sizeof *fd);
95438889Sjdp  fd->next = NULL;
95538889Sjdp  fd->index = fonts;
95638889Sjdp  fd->length = fontdatalength;
95738889Sjdp  fd->data = fontdata;
95838889Sjdp
95938889Sjdp  for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
96038889Sjdp    ;
96138889Sjdp  *pp = fd;
96238889Sjdp
96338889Sjdp  /* For the single fontdirs resource, we always use the resource
96438889Sjdp     information of the last font.  I don't know what else to do.  */
96538889Sjdp  fontdirs_resinfo = *resinfo;
96638889Sjdp}
96738889Sjdp
96838889Sjdp/* Define the fontdirs resource.  This is called after the entire rc
96938889Sjdp   file has been parsed, if any font resources were seen.  */
97038889Sjdp
97138889Sjdpstatic void
97238889Sjdpdefine_fontdirs ()
97338889Sjdp{
97438889Sjdp  struct res_resource *r;
97538889Sjdp  struct res_id id;
97638889Sjdp
97738889Sjdp  id.named = 0;
97838889Sjdp  id.u.id = 1;
97938889Sjdp
98038889Sjdp  r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
98138889Sjdp
98238889Sjdp  r->type = RES_TYPE_FONTDIR;
98338889Sjdp  r->u.fontdir = fontdirs;
98438889Sjdp  r->res_info = fontdirs_resinfo;
98538889Sjdp}
98638889Sjdp
98738889Sjdp/* Define an icon resource.  An icon file may contain a set of
98838889Sjdp   bitmaps, each representing the same icon at various different
98938889Sjdp   resolutions.  They each get written out with a different ID.  The
99038889Sjdp   real icon resource is then a group resource which can be used to
99138889Sjdp   select one of the actual icon bitmaps.  */
99238889Sjdp
99338889Sjdpvoid
99438889Sjdpdefine_icon (id, resinfo, filename)
99538889Sjdp     struct res_id id;
99638889Sjdp     const struct res_res_info *resinfo;
99738889Sjdp     const char *filename;
99838889Sjdp{
99938889Sjdp  FILE *e;
100038889Sjdp  char *real_filename;
100138889Sjdp  int type, count, i;
100238889Sjdp  struct icondir *icondirs;
100338889Sjdp  int first_icon;
100438889Sjdp  struct res_resource *r;
100538889Sjdp  struct group_icon *first, **pp;
100638889Sjdp
100738889Sjdp  e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
100838889Sjdp
100938889Sjdp  /* The start of an icon file is a three word structure.  The first
101038889Sjdp     word is ignored.  The second word is the type of data.  The third
101138889Sjdp     word is the number of entries.  */
101238889Sjdp
101338889Sjdp  get_word (e, real_filename);
101438889Sjdp  type = get_word (e, real_filename);
101538889Sjdp  count = get_word (e, real_filename);
101638889Sjdp  if (type != 1)
101760484Sobrien    fatal (_("icon file `%s' does not contain icon data"), real_filename);
101838889Sjdp
101938889Sjdp  /* Read in the icon directory entries.  */
102038889Sjdp
102138889Sjdp  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
102238889Sjdp
102338889Sjdp  for (i = 0; i < count; i++)
102438889Sjdp    {
102538889Sjdp      icondirs[i].width = getc (e);
102638889Sjdp      icondirs[i].height = getc (e);
102738889Sjdp      icondirs[i].colorcount = getc (e);
102838889Sjdp      getc (e);
102938889Sjdp      icondirs[i].u.icon.planes = get_word (e, real_filename);
103038889Sjdp      icondirs[i].u.icon.bits = get_word (e, real_filename);
103138889Sjdp      icondirs[i].bytes = get_long (e, real_filename);
103238889Sjdp      icondirs[i].offset = get_long (e, real_filename);
103338889Sjdp
103438889Sjdp      if (feof (e))
103538889Sjdp	unexpected_eof (real_filename);
103638889Sjdp    }
103738889Sjdp
103838889Sjdp  /* Define each icon as a unique resource.  */
103938889Sjdp
104038889Sjdp  first_icon = icons;
104138889Sjdp
104238889Sjdp  for (i = 0; i < count; i++)
104338889Sjdp    {
104438889Sjdp      unsigned char *data;
104538889Sjdp      struct res_id name;
104638889Sjdp
104738889Sjdp      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
104860484Sobrien	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
104938889Sjdp	       icondirs[i].offset, strerror (errno));
105038889Sjdp
105138889Sjdp      data = (unsigned char *) res_alloc (icondirs[i].bytes);
105238889Sjdp
105338889Sjdp      get_data (e, data, icondirs[i].bytes, real_filename);
105438889Sjdp
105538889Sjdp      ++icons;
105638889Sjdp
105738889Sjdp      name.named = 0;
105838889Sjdp      name.u.id = icons;
105938889Sjdp
106038889Sjdp      r = define_standard_resource (&resources, RT_ICON, name,
106138889Sjdp				    resinfo->language, 0);
106238889Sjdp      r->type = RES_TYPE_ICON;
106338889Sjdp      r->u.data.length = icondirs[i].bytes;
106438889Sjdp      r->u.data.data = data;
106538889Sjdp      r->res_info = *resinfo;
106638889Sjdp    }
106738889Sjdp
106838889Sjdp  fclose (e);
106938889Sjdp  free (real_filename);
107038889Sjdp
107138889Sjdp  /* Define an icon group resource.  */
107238889Sjdp
107338889Sjdp  first = NULL;
107438889Sjdp  pp = &first;
107538889Sjdp  for (i = 0; i < count; i++)
107638889Sjdp    {
107738889Sjdp      struct group_icon *cg;
107838889Sjdp
107938889Sjdp      /* For some reason, at least in some files the planes and bits
108038889Sjdp         are zero.  We instead set them from the color.  This is
108138889Sjdp         copied from rcl.  */
108238889Sjdp
108338889Sjdp      cg = (struct group_icon *) res_alloc (sizeof *cg);
108438889Sjdp      cg->next = NULL;
108538889Sjdp      cg->width = icondirs[i].width;
108638889Sjdp      cg->height = icondirs[i].height;
108738889Sjdp      cg->colors = icondirs[i].colorcount;
108838889Sjdp
108938889Sjdp      cg->planes = 1;
109038889Sjdp      cg->bits = 0;
109138889Sjdp      while ((1 << cg->bits) < cg->colors)
109238889Sjdp	++cg->bits;
109338889Sjdp
109438889Sjdp      cg->bytes = icondirs[i].bytes;
109538889Sjdp      cg->index = first_icon + i + 1;
109638889Sjdp
109738889Sjdp      *pp = cg;
109838889Sjdp      pp = &(*pp)->next;
109938889Sjdp    }
110038889Sjdp
110138889Sjdp  free (icondirs);
110238889Sjdp
110338889Sjdp  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
110438889Sjdp				resinfo->language, 0);
110538889Sjdp  r->type = RES_TYPE_GROUP_ICON;
110638889Sjdp  r->u.group_icon = first;
110738889Sjdp  r->res_info = *resinfo;
110838889Sjdp}
110938889Sjdp
111038889Sjdp/* Define a menu resource.  */
111138889Sjdp
111238889Sjdpvoid
111338889Sjdpdefine_menu (id, resinfo, menuitems)
111438889Sjdp     struct res_id id;
111538889Sjdp     const struct res_res_info *resinfo;
111638889Sjdp     struct menuitem *menuitems;
111738889Sjdp{
111838889Sjdp  struct menu *m;
111938889Sjdp  struct res_resource *r;
112038889Sjdp
112138889Sjdp  m = (struct menu *) res_alloc (sizeof *m);
112238889Sjdp  m->items = menuitems;
112338889Sjdp  m->help = 0;
112438889Sjdp
112538889Sjdp  r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
112638889Sjdp  r->type = RES_TYPE_MENU;
112738889Sjdp  r->u.menu = m;
112838889Sjdp  r->res_info = *resinfo;
112938889Sjdp}
113038889Sjdp
113138889Sjdp/* Define a menu item.  This does not define a resource, but merely
113238889Sjdp   allocates and fills in a structure.  */
113338889Sjdp
113438889Sjdpstruct menuitem *
113538889Sjdpdefine_menuitem (text, menuid, type, state, help, menuitems)
113638889Sjdp     const char *text;
113738889Sjdp     int menuid;
113838889Sjdp     unsigned long type;
113938889Sjdp     unsigned long state;
114038889Sjdp     unsigned long help;
114138889Sjdp     struct menuitem *menuitems;
114238889Sjdp{
114338889Sjdp  struct menuitem *mi;
114438889Sjdp
114538889Sjdp  mi = (struct menuitem *) res_alloc (sizeof *mi);
114638889Sjdp  mi->next = NULL;
114738889Sjdp  mi->type = type;
114838889Sjdp  mi->state = state;
114938889Sjdp  mi->id = menuid;
115038889Sjdp  if (text == NULL)
115138889Sjdp    mi->text = NULL;
115238889Sjdp  else
115338889Sjdp    unicode_from_ascii ((int *) NULL, &mi->text, text);
115438889Sjdp  mi->help = help;
115538889Sjdp  mi->popup = menuitems;
115638889Sjdp  return mi;
115738889Sjdp}
115838889Sjdp
115938889Sjdp/* Define a messagetable resource.  */
116038889Sjdp
116138889Sjdpvoid
116238889Sjdpdefine_messagetable (id, resinfo, filename)
116338889Sjdp     struct res_id id;
116438889Sjdp     const struct res_res_info *resinfo;
116538889Sjdp     const char *filename;
116638889Sjdp{
116738889Sjdp  FILE *e;
116838889Sjdp  char *real_filename;
116938889Sjdp  struct stat s;
117038889Sjdp  unsigned char *data;
117138889Sjdp  struct res_resource *r;
117238889Sjdp
117338889Sjdp  e = open_file_search (filename, FOPEN_RB, "messagetable file",
117438889Sjdp			&real_filename);
117538889Sjdp
117638889Sjdp  if (stat (real_filename, &s) < 0)
117760484Sobrien    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
117838889Sjdp	   strerror (errno));
117938889Sjdp
118038889Sjdp  data = (unsigned char *) res_alloc (s.st_size);
118138889Sjdp
118238889Sjdp  get_data (e, data, s.st_size, real_filename);
118338889Sjdp
118438889Sjdp  fclose (e);
118538889Sjdp  free (real_filename);
118638889Sjdp
118738889Sjdp  r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
118838889Sjdp				resinfo->language, 0);
118938889Sjdp
119038889Sjdp  r->type = RES_TYPE_MESSAGETABLE;
119138889Sjdp  r->u.data.length = s.st_size;
119238889Sjdp  r->u.data.data = data;
119338889Sjdp  r->res_info = *resinfo;
119438889Sjdp}
119538889Sjdp
119638889Sjdp/* Define an rcdata resource.  */
119738889Sjdp
119838889Sjdpvoid
119938889Sjdpdefine_rcdata (id, resinfo, data)
120038889Sjdp     struct res_id id;
120138889Sjdp     const struct res_res_info *resinfo;
120238889Sjdp     struct rcdata_item *data;
120338889Sjdp{
120438889Sjdp  struct res_resource *r;
120538889Sjdp
120638889Sjdp  r = define_standard_resource (&resources, RT_RCDATA, id,
120738889Sjdp				resinfo->language, 0);
120838889Sjdp  r->type = RES_TYPE_RCDATA;
120938889Sjdp  r->u.rcdata = data;
121038889Sjdp  r->res_info = *resinfo;
121138889Sjdp}
121238889Sjdp
121338889Sjdp/* Create an rcdata item holding a string.  */
121438889Sjdp
121538889Sjdpstruct rcdata_item *
121638889Sjdpdefine_rcdata_string (string, len)
121738889Sjdp     const char *string;
121838889Sjdp     unsigned long len;
121938889Sjdp{
122038889Sjdp  struct rcdata_item *ri;
122138889Sjdp  char *s;
122238889Sjdp
122338889Sjdp  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
122438889Sjdp  ri->next = NULL;
122538889Sjdp  ri->type = RCDATA_STRING;
122638889Sjdp  ri->u.string.length = len;
122738889Sjdp  s = (char *) res_alloc (len);
122838889Sjdp  memcpy (s, string, len);
122938889Sjdp  ri->u.string.s = s;
123038889Sjdp
123138889Sjdp  return ri;
123238889Sjdp}
123338889Sjdp
123438889Sjdp/* Create an rcdata item holding a number.  */
123538889Sjdp
123638889Sjdpstruct rcdata_item *
123738889Sjdpdefine_rcdata_number (val, dword)
123838889Sjdp     unsigned long val;
123938889Sjdp     int dword;
124038889Sjdp{
124138889Sjdp  struct rcdata_item *ri;
124238889Sjdp
124338889Sjdp  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
124438889Sjdp  ri->next = NULL;
124538889Sjdp  ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
124638889Sjdp  ri->u.word = val;
124738889Sjdp
124838889Sjdp  return ri;
124938889Sjdp}
125038889Sjdp
125138889Sjdp/* Define a stringtable resource.  This is called for each string
125238889Sjdp   which appears in a STRINGTABLE statement.  */
125338889Sjdp
125438889Sjdpvoid
125538889Sjdpdefine_stringtable (resinfo, stringid, string)
125638889Sjdp     const struct res_res_info *resinfo;
125738889Sjdp     unsigned long stringid;
125838889Sjdp     const char *string;
125938889Sjdp{
126038889Sjdp  struct res_id id;
126138889Sjdp  struct res_resource *r;
126238889Sjdp
126338889Sjdp  id.named = 0;
126438889Sjdp  id.u.id = (stringid >> 4) + 1;
126538889Sjdp  r = define_standard_resource (&resources, RT_STRING, id,
126638889Sjdp				resinfo->language, 1);
126738889Sjdp
126838889Sjdp  if (r->type == RES_TYPE_UNINITIALIZED)
126938889Sjdp    {
127038889Sjdp      int i;
127138889Sjdp
127238889Sjdp      r->type = RES_TYPE_STRINGTABLE;
127338889Sjdp      r->u.stringtable = ((struct stringtable *)
127438889Sjdp			  res_alloc (sizeof (struct stringtable)));
127538889Sjdp      for (i = 0; i < 16; i++)
127638889Sjdp	{
127738889Sjdp	  r->u.stringtable->strings[i].length = 0;
127838889Sjdp	  r->u.stringtable->strings[i].string = NULL;
127938889Sjdp	}
128038889Sjdp
128138889Sjdp      r->res_info = *resinfo;
128238889Sjdp    }
128338889Sjdp
128438889Sjdp  unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
128538889Sjdp		      &r->u.stringtable->strings[stringid & 0xf].string,
128638889Sjdp		      string);
128738889Sjdp}
128838889Sjdp
128938889Sjdp/* Define a user data resource where the data is in the rc file.  */
129038889Sjdp
129138889Sjdpvoid
129238889Sjdpdefine_user_data (id, type, resinfo, data)
129338889Sjdp     struct res_id id;
129438889Sjdp     struct res_id type;
129538889Sjdp     const struct res_res_info *resinfo;
129638889Sjdp     struct rcdata_item *data;
129738889Sjdp{
129838889Sjdp  struct res_id ids[3];
129938889Sjdp  struct res_resource *r;
130038889Sjdp
130138889Sjdp  ids[0] = type;
130238889Sjdp  ids[1] = id;
130338889Sjdp  ids[2].named = 0;
130438889Sjdp  ids[2].u.id = resinfo->language;
130538889Sjdp
130638889Sjdp  r = define_resource (&resources, 3, ids, 0);
130738889Sjdp  r->type = RES_TYPE_USERDATA;
130838889Sjdp  r->u.userdata = data;
130938889Sjdp  r->res_info = *resinfo;
131038889Sjdp}
131138889Sjdp
131238889Sjdp/* Define a user data resource where the data is in a file.  */
131338889Sjdp
131438889Sjdpvoid
131538889Sjdpdefine_user_file (id, type, resinfo, filename)
131638889Sjdp     struct res_id id;
131738889Sjdp     struct res_id type;
131838889Sjdp     const struct res_res_info *resinfo;
131938889Sjdp     const char *filename;
132038889Sjdp{
132138889Sjdp  FILE *e;
132238889Sjdp  char *real_filename;
132338889Sjdp  struct stat s;
132438889Sjdp  unsigned char *data;
132538889Sjdp  struct res_id ids[3];
132638889Sjdp  struct res_resource *r;
132738889Sjdp
132838889Sjdp  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
132938889Sjdp
133038889Sjdp  if (stat (real_filename, &s) < 0)
133160484Sobrien    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
133238889Sjdp	   strerror (errno));
133338889Sjdp
133438889Sjdp  data = (unsigned char *) res_alloc (s.st_size);
133538889Sjdp
133638889Sjdp  get_data (e, data, s.st_size, real_filename);
133738889Sjdp
133838889Sjdp  fclose (e);
133938889Sjdp  free (real_filename);
134038889Sjdp
134138889Sjdp  ids[0] = type;
134238889Sjdp  ids[1] = id;
134338889Sjdp  ids[2].named = 0;
134438889Sjdp  ids[2].u.id = resinfo->language;
134538889Sjdp
134638889Sjdp  r = define_resource (&resources, 3, ids, 0);
134738889Sjdp  r->type = RES_TYPE_USERDATA;
134838889Sjdp  r->u.userdata = ((struct rcdata_item *)
134938889Sjdp		   res_alloc (sizeof (struct rcdata_item)));
135038889Sjdp  r->u.userdata->next = NULL;
135138889Sjdp  r->u.userdata->type = RCDATA_BUFFER;
135238889Sjdp  r->u.userdata->u.buffer.length = s.st_size;
135338889Sjdp  r->u.userdata->u.buffer.data = data;
135438889Sjdp  r->res_info = *resinfo;
135538889Sjdp}
135638889Sjdp
135738889Sjdp/* Define a versioninfo resource.  */
135838889Sjdp
135938889Sjdpvoid
136038889Sjdpdefine_versioninfo (id, language, fixedverinfo, verinfo)
136138889Sjdp     struct res_id id;
136238889Sjdp     int language;
136338889Sjdp     struct fixed_versioninfo *fixedverinfo;
136438889Sjdp     struct ver_info *verinfo;
136538889Sjdp{
136638889Sjdp  struct res_resource *r;
136738889Sjdp
136838889Sjdp  r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
136938889Sjdp  r->type = RES_TYPE_VERSIONINFO;
137038889Sjdp  r->u.versioninfo = ((struct versioninfo *)
137138889Sjdp		      res_alloc (sizeof (struct versioninfo)));
137238889Sjdp  r->u.versioninfo->fixed = fixedverinfo;
137338889Sjdp  r->u.versioninfo->var = verinfo;
137438889Sjdp  r->res_info.language = language;
137538889Sjdp}
137638889Sjdp
137738889Sjdp/* Add string version info to a list of version information.  */
137838889Sjdp
137938889Sjdpstruct ver_info *
138038889Sjdpappend_ver_stringfileinfo (verinfo, language, strings)
138138889Sjdp     struct ver_info *verinfo;
138238889Sjdp     const char *language;
138338889Sjdp     struct ver_stringinfo *strings;
138438889Sjdp{
138538889Sjdp  struct ver_info *vi, **pp;
138638889Sjdp
138738889Sjdp  vi = (struct ver_info *) res_alloc (sizeof *vi);
138838889Sjdp  vi->next = NULL;
138938889Sjdp  vi->type = VERINFO_STRING;
139038889Sjdp  unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
139138889Sjdp  vi->u.string.strings = strings;
139238889Sjdp
139338889Sjdp  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
139438889Sjdp    ;
139538889Sjdp  *pp = vi;
139638889Sjdp
139738889Sjdp  return verinfo;
139838889Sjdp}
139938889Sjdp
140038889Sjdp/* Add variable version info to a list of version information.  */
140138889Sjdp
140238889Sjdpstruct ver_info *
140338889Sjdpappend_ver_varfileinfo (verinfo, key, var)
140438889Sjdp     struct ver_info *verinfo;
140538889Sjdp     const char *key;
140638889Sjdp     struct ver_varinfo *var;
140738889Sjdp{
140838889Sjdp  struct ver_info *vi, **pp;
140938889Sjdp
141038889Sjdp  vi = (struct ver_info *) res_alloc (sizeof *vi);
141138889Sjdp  vi->next = NULL;
141238889Sjdp  vi->type = VERINFO_VAR;
141338889Sjdp  unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
141438889Sjdp  vi->u.var.var = var;
141538889Sjdp
141638889Sjdp  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
141738889Sjdp    ;
141838889Sjdp  *pp = vi;
141938889Sjdp
142038889Sjdp  return verinfo;
142138889Sjdp}
142238889Sjdp
142338889Sjdp/* Append version string information to a list.  */
142438889Sjdp
142538889Sjdpstruct ver_stringinfo *
142638889Sjdpappend_verval (strings, key, value)
142738889Sjdp     struct ver_stringinfo *strings;
142838889Sjdp     const char *key;
142938889Sjdp     const char *value;
143038889Sjdp{
143138889Sjdp  struct ver_stringinfo *vs, **pp;
143238889Sjdp
143338889Sjdp  vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
143438889Sjdp  vs->next = NULL;
143538889Sjdp  unicode_from_ascii ((int *) NULL, &vs->key, key);
143638889Sjdp  unicode_from_ascii ((int *) NULL, &vs->value, value);
143738889Sjdp
143838889Sjdp  for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
143938889Sjdp    ;
144038889Sjdp  *pp = vs;
144138889Sjdp
144238889Sjdp  return strings;
144338889Sjdp}
144438889Sjdp
144538889Sjdp/* Append version variable information to a list.  */
144638889Sjdp
144738889Sjdpstruct ver_varinfo *
144838889Sjdpappend_vertrans (var, language, charset)
144938889Sjdp     struct ver_varinfo *var;
145038889Sjdp     unsigned long language;
145138889Sjdp     unsigned long charset;
145238889Sjdp{
145338889Sjdp  struct ver_varinfo *vv, **pp;
145438889Sjdp
145538889Sjdp  vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
145638889Sjdp  vv->next = NULL;
145738889Sjdp  vv->language = language;
145838889Sjdp  vv->charset = charset;
145938889Sjdp
146038889Sjdp  for (pp = &var; *pp != NULL; pp = &(*pp)->next)
146138889Sjdp    ;
146238889Sjdp  *pp = vv;
146338889Sjdp
146438889Sjdp  return var;
146538889Sjdp}
146638889Sjdp
146738889Sjdp/* Local functions used to write out an rc file.  */
146838889Sjdp
146938889Sjdpstatic void indent PARAMS ((FILE *, int));
147038889Sjdpstatic void write_rc_directory
147138889Sjdp  PARAMS ((FILE *, const struct res_directory *, const struct res_id *,
147238889Sjdp	   const struct res_id *, int *, int));
147338889Sjdpstatic void write_rc_subdir
147438889Sjdp  PARAMS ((FILE *, const struct res_entry *, const struct res_id *,
147538889Sjdp	   const struct res_id *, int *, int));
147638889Sjdpstatic void write_rc_resource
147738889Sjdp  PARAMS ((FILE *, const struct res_id *, const struct res_id *,
147838889Sjdp	   const struct res_resource *, int *));
147938889Sjdpstatic void write_rc_accelerators
148038889Sjdp  PARAMS ((FILE *, const struct accelerator *));
148138889Sjdpstatic void write_rc_cursor PARAMS ((FILE *, const struct cursor *));
148238889Sjdpstatic void write_rc_group_cursor
148338889Sjdp  PARAMS ((FILE *, const struct group_cursor *));
148438889Sjdpstatic void write_rc_dialog PARAMS ((FILE *, const struct dialog *));
148538889Sjdpstatic void write_rc_dialog_control
148638889Sjdp  PARAMS ((FILE *, const struct dialog_control *));
148738889Sjdpstatic void write_rc_fontdir PARAMS ((FILE *, const struct fontdir *));
148838889Sjdpstatic void write_rc_group_icon PARAMS ((FILE *, const struct group_icon *));
148938889Sjdpstatic void write_rc_menu PARAMS ((FILE *, const struct menu *, int));
149038889Sjdpstatic void write_rc_menuitems
149138889Sjdp  PARAMS ((FILE *, const struct menuitem *, int, int));
149238889Sjdpstatic void write_rc_rcdata PARAMS ((FILE *, const struct rcdata_item *, int));
149338889Sjdpstatic void write_rc_stringtable
149438889Sjdp  PARAMS ((FILE *, const struct res_id *, const struct stringtable *));
149538889Sjdpstatic void write_rc_versioninfo PARAMS ((FILE *, const struct versioninfo *));
149638889Sjdpstatic void write_rc_filedata
149738889Sjdp  PARAMS ((FILE *, unsigned long, const unsigned char *));
149838889Sjdp
149938889Sjdp/* Indent a given number of spaces.  */
150038889Sjdp
150138889Sjdpstatic void
150238889Sjdpindent (e, c)
150338889Sjdp     FILE *e;
150438889Sjdp     int c;
150538889Sjdp{
150638889Sjdp  int i;
150738889Sjdp
150838889Sjdp  for (i = 0; i < c; i++)
150938889Sjdp    putc (' ', e);
151038889Sjdp}
151138889Sjdp
151238889Sjdp/* Dump the resources we have read in the format of an rc file.
151338889Sjdp
151438889Sjdp   Actually, we don't use the format of an rc file, because it's way
151538889Sjdp   too much of a pain--for example, we'd have to write icon resources
151638889Sjdp   into a file and refer to that file.  We just generate a readable
151738889Sjdp   format that kind of looks like an rc file, and is useful for
151838889Sjdp   understanding the contents of a resource file.  Someday we may want
151938889Sjdp   to generate an rc file which the rc compiler can read; if that day
152038889Sjdp   comes, this code will have to be fixed up.  */
152138889Sjdp
152238889Sjdpvoid
152338889Sjdpwrite_rc_file (filename, resources)
152438889Sjdp     const char *filename;
152538889Sjdp     const struct res_directory *resources;
152638889Sjdp{
152738889Sjdp  FILE *e;
152838889Sjdp  int language;
152938889Sjdp
153038889Sjdp  if (filename == NULL)
153138889Sjdp    e = stdout;
153238889Sjdp  else
153338889Sjdp    {
153438889Sjdp      e = fopen (filename, FOPEN_WT);
153538889Sjdp      if (e == NULL)
153660484Sobrien	fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
153738889Sjdp    }
153838889Sjdp
153938889Sjdp  language = -1;
154038889Sjdp  write_rc_directory (e, resources, (const struct res_id *) NULL,
154138889Sjdp		      (const struct res_id *) NULL, &language, 1);
154238889Sjdp}
154338889Sjdp
154438889Sjdp/* Write out a directory.  E is the file to write to.  RD is the
154538889Sjdp   directory.  TYPE is a pointer to the level 1 ID which serves as the
154638889Sjdp   resource type.  NAME is a pointer to the level 2 ID which serves as
154738889Sjdp   an individual resource name.  LANGUAGE is a pointer to the current
154838889Sjdp   language.  LEVEL is the level in the tree.  */
154938889Sjdp
155038889Sjdpstatic void
155138889Sjdpwrite_rc_directory (e, rd, type, name, language, level)
155238889Sjdp     FILE *e;
155338889Sjdp     const struct res_directory *rd;
155438889Sjdp     const struct res_id *type;
155538889Sjdp     const struct res_id *name;
155638889Sjdp     int *language;
155738889Sjdp     int level;
155838889Sjdp{
155938889Sjdp  const struct res_entry *re;
156038889Sjdp
156138889Sjdp  /* Print out some COFF information that rc files can't represent.  */
156238889Sjdp
156338889Sjdp  if (rd->time != 0)
156438889Sjdp    fprintf (e, "// Time stamp: %lu\n", rd->time);
156538889Sjdp  if (rd->characteristics != 0)
156638889Sjdp    fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
156738889Sjdp  if (rd->major != 0 || rd->minor != 0)
156838889Sjdp    fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
156938889Sjdp
157038889Sjdp  for (re = rd->entries;  re != NULL; re = re->next)
157138889Sjdp    {
157238889Sjdp      switch (level)
157338889Sjdp	{
157438889Sjdp	case 1:
157538889Sjdp	  /* If we're at level 1, the key of this resource is the
157638889Sjdp             type.  This normally duplicates the information we have
157738889Sjdp             stored with the resource itself, but we need to remember
157838889Sjdp             the type if this is a user define resource type.  */
157938889Sjdp	  type = &re->id;
158038889Sjdp	  break;
158138889Sjdp
158238889Sjdp	case 2:
158338889Sjdp	  /* If we're at level 2, the key of this resource is the name
158499461Sobrien	     we are going to use in the rc printout.  */
158538889Sjdp	  name = &re->id;
158638889Sjdp	  break;
158738889Sjdp
158838889Sjdp	case 3:
158938889Sjdp	  /* If we're at level 3, then this key represents a language.
159038889Sjdp	     Use it to update the current language.  */
159138889Sjdp	  if (! re->id.named
159260484Sobrien	      && re->id.u.id != (unsigned long) (unsigned int) *language
159338889Sjdp	      && (re->id.u.id & 0xffff) == re->id.u.id)
159438889Sjdp	    {
159538889Sjdp	      fprintf (e, "LANGUAGE %lu, %lu\n",
1596104834Sobrien		       re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
159799461Sobrien		       (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
159838889Sjdp	      *language = re->id.u.id;
159938889Sjdp	    }
160038889Sjdp	  break;
160138889Sjdp
160238889Sjdp	default:
160338889Sjdp	  break;
160438889Sjdp	}
160538889Sjdp
160638889Sjdp      if (re->subdir)
160738889Sjdp	write_rc_subdir (e, re, type, name, language, level);
160838889Sjdp      else
160938889Sjdp	{
161038889Sjdp	  if (level == 3)
161138889Sjdp	    {
161238889Sjdp	      /* This is the normal case: the three levels are
161338889Sjdp                 TYPE/NAME/LANGUAGE.  NAME will have been set at level
161438889Sjdp                 2, and represents the name to use.  We probably just
161538889Sjdp                 set LANGUAGE, and it will probably match what the
161638889Sjdp                 resource itself records if anything.  */
161738889Sjdp	      write_rc_resource (e, type, name, re->u.res, language);
161838889Sjdp	    }
161938889Sjdp	  else
162038889Sjdp	    {
162138889Sjdp	      fprintf (e, "// Resource at unexpected level %d\n", level);
162238889Sjdp	      write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
162338889Sjdp				 language);
162438889Sjdp	    }
162538889Sjdp	}
162638889Sjdp    }
162738889Sjdp}
162838889Sjdp
162938889Sjdp/* Write out a subdirectory entry.  E is the file to write to.  RE is
163038889Sjdp   the subdirectory entry.  TYPE and NAME are pointers to higher level
163138889Sjdp   IDs, or NULL.  LANGUAGE is a pointer to the current language.
163238889Sjdp   LEVEL is the level in the tree.  */
163338889Sjdp
163438889Sjdpstatic void
163538889Sjdpwrite_rc_subdir (e, re, type, name, language, level)
163638889Sjdp     FILE *e;
163738889Sjdp     const struct res_entry *re;
163838889Sjdp     const struct res_id *type;
163938889Sjdp     const struct res_id *name;
164038889Sjdp     int *language;
164138889Sjdp     int level;
164238889Sjdp{
164338889Sjdp  fprintf (e, "\n");
164438889Sjdp  switch (level)
164538889Sjdp    {
164638889Sjdp    case 1:
164738889Sjdp      fprintf (e, "// Type: ");
164838889Sjdp      if (re->id.named)
164938889Sjdp	res_id_print (e, re->id, 1);
165038889Sjdp      else
165138889Sjdp	{
165238889Sjdp	  const char *s;
165338889Sjdp
165438889Sjdp	  switch (re->id.u.id)
165538889Sjdp	    {
165638889Sjdp	    case RT_CURSOR: s = "cursor"; break;
165738889Sjdp	    case RT_BITMAP: s = "bitmap"; break;
165838889Sjdp	    case RT_ICON: s = "icon"; break;
165938889Sjdp	    case RT_MENU: s = "menu"; break;
166038889Sjdp	    case RT_DIALOG: s = "dialog"; break;
166138889Sjdp	    case RT_STRING: s = "stringtable"; break;
166238889Sjdp	    case RT_FONTDIR: s = "fontdir"; break;
166338889Sjdp	    case RT_FONT: s = "font"; break;
166460484Sobrien	    case RT_ACCELERATOR: s = "accelerators"; break;
166538889Sjdp	    case RT_RCDATA: s = "rcdata"; break;
166638889Sjdp	    case RT_MESSAGETABLE: s = "messagetable"; break;
166738889Sjdp	    case RT_GROUP_CURSOR: s = "group cursor"; break;
166838889Sjdp	    case RT_GROUP_ICON: s = "group icon"; break;
166938889Sjdp	    case RT_VERSION: s = "version"; break;
167038889Sjdp	    case RT_DLGINCLUDE: s = "dlginclude"; break;
167138889Sjdp	    case RT_PLUGPLAY: s = "plugplay"; break;
167238889Sjdp	    case RT_VXD: s = "vxd"; break;
167338889Sjdp	    case RT_ANICURSOR: s = "anicursor"; break;
167438889Sjdp	    case RT_ANIICON: s = "aniicon"; break;
167538889Sjdp	    default: s = NULL; break;
167638889Sjdp	    }
167738889Sjdp
167838889Sjdp	  if (s != NULL)
167938889Sjdp	    fprintf (e, "%s", s);
168038889Sjdp	  else
168138889Sjdp	    res_id_print (e, re->id, 1);
168238889Sjdp	}
168338889Sjdp      fprintf (e, "\n");
168438889Sjdp      break;
168538889Sjdp
168638889Sjdp    case 2:
168738889Sjdp      fprintf (e, "// Name: ");
168838889Sjdp      res_id_print (e, re->id, 1);
168938889Sjdp      fprintf (e, "\n");
169038889Sjdp      break;
169138889Sjdp
169238889Sjdp    case 3:
169338889Sjdp      fprintf (e, "// Language: ");
169438889Sjdp      res_id_print (e, re->id, 1);
169538889Sjdp      fprintf (e, "\n");
169638889Sjdp      break;
169738889Sjdp
169838889Sjdp    default:
169938889Sjdp      fprintf (e, "// Level %d: ", level);
170038889Sjdp      res_id_print (e, re->id, 1);
170138889Sjdp      fprintf (e, "\n");
1702104834Sobrien    }
170338889Sjdp
170438889Sjdp  write_rc_directory (e, re->u.dir, type, name, language, level + 1);
170538889Sjdp}
170638889Sjdp
170738889Sjdp/* Write out a single resource.  E is the file to write to.  TYPE is a
170838889Sjdp   pointer to the type of the resource.  NAME is a pointer to the name
170938889Sjdp   of the resource; it will be NULL if there is a level mismatch.  RES
171038889Sjdp   is the resource data.  LANGUAGE is a pointer to the current
171138889Sjdp   language.  */
171238889Sjdp
171338889Sjdpstatic void
171438889Sjdpwrite_rc_resource (e, type, name, res, language)
171538889Sjdp     FILE *e;
171638889Sjdp     const struct res_id *type;
171738889Sjdp     const struct res_id *name;
171838889Sjdp     const struct res_resource *res;
171938889Sjdp     int *language;
172038889Sjdp{
172138889Sjdp  const char *s;
172238889Sjdp  int rt;
172338889Sjdp  int menuex = 0;
172438889Sjdp
172538889Sjdp  fprintf (e, "\n");
172638889Sjdp
172738889Sjdp  switch (res->type)
172838889Sjdp    {
172938889Sjdp    default:
173038889Sjdp      abort ();
173138889Sjdp
173238889Sjdp    case RES_TYPE_ACCELERATOR:
173338889Sjdp      s = "ACCELERATOR";
173460484Sobrien      rt = RT_ACCELERATOR;
173538889Sjdp      break;
173638889Sjdp
173738889Sjdp    case RES_TYPE_BITMAP:
173838889Sjdp      s = "BITMAP";
173938889Sjdp      rt = RT_BITMAP;
174038889Sjdp      break;
174138889Sjdp
174238889Sjdp    case RES_TYPE_CURSOR:
174338889Sjdp      s = "CURSOR";
174438889Sjdp      rt = RT_CURSOR;
174538889Sjdp      break;
174638889Sjdp
174738889Sjdp    case RES_TYPE_GROUP_CURSOR:
174838889Sjdp      s = "GROUP_CURSOR";
174938889Sjdp      rt = RT_GROUP_CURSOR;
175038889Sjdp      break;
175138889Sjdp
175238889Sjdp    case RES_TYPE_DIALOG:
175338889Sjdp      if (extended_dialog (res->u.dialog))
175438889Sjdp	s = "DIALOGEX";
175538889Sjdp      else
175638889Sjdp	s = "DIALOG";
175738889Sjdp      rt = RT_DIALOG;
175838889Sjdp      break;
175938889Sjdp
176038889Sjdp    case RES_TYPE_FONT:
176138889Sjdp      s = "FONT";
176238889Sjdp      rt = RT_FONT;
176338889Sjdp      break;
176438889Sjdp
176538889Sjdp    case RES_TYPE_FONTDIR:
176638889Sjdp      s = "FONTDIR";
176738889Sjdp      rt = RT_FONTDIR;
176838889Sjdp      break;
176938889Sjdp
177038889Sjdp    case RES_TYPE_ICON:
177138889Sjdp      s = "ICON";
177238889Sjdp      rt = RT_ICON;
177338889Sjdp      break;
177438889Sjdp
177538889Sjdp    case RES_TYPE_GROUP_ICON:
177638889Sjdp      s = "GROUP_ICON";
177738889Sjdp      rt = RT_GROUP_ICON;
177838889Sjdp      break;
177938889Sjdp
178038889Sjdp    case RES_TYPE_MENU:
178138889Sjdp      if (extended_menu (res->u.menu))
178238889Sjdp	{
178338889Sjdp	  s = "MENUEX";
178438889Sjdp	  menuex = 1;
178538889Sjdp	}
178638889Sjdp      else
178738889Sjdp	{
178838889Sjdp	  s = "MENU";
178938889Sjdp	  menuex = 0;
179038889Sjdp	}
179138889Sjdp      rt = RT_MENU;
179238889Sjdp      break;
179338889Sjdp
179438889Sjdp    case RES_TYPE_MESSAGETABLE:
179538889Sjdp      s = "MESSAGETABLE";
179638889Sjdp      rt = RT_MESSAGETABLE;
179738889Sjdp      break;
179838889Sjdp
179938889Sjdp    case RES_TYPE_RCDATA:
180038889Sjdp      s = "RCDATA";
180138889Sjdp      rt = RT_RCDATA;
180238889Sjdp      break;
180338889Sjdp
180438889Sjdp    case RES_TYPE_STRINGTABLE:
180538889Sjdp      s = "STRINGTABLE";
180638889Sjdp      rt = RT_STRING;
180738889Sjdp      break;
180838889Sjdp
180938889Sjdp    case RES_TYPE_USERDATA:
181038889Sjdp      s = NULL;
181138889Sjdp      rt = 0;
181238889Sjdp      break;
181338889Sjdp
181438889Sjdp    case RES_TYPE_VERSIONINFO:
181538889Sjdp      s = "VERSIONINFO";
181638889Sjdp      rt = RT_VERSION;
181738889Sjdp      break;
181838889Sjdp    }
181938889Sjdp
182038889Sjdp  if (rt != 0
182138889Sjdp      && type != NULL
182260484Sobrien      && (type->named || type->u.id != (unsigned long) rt))
182338889Sjdp    {
182438889Sjdp      fprintf (e, "// Unexpected resource type mismatch: ");
182538889Sjdp      res_id_print (e, *type, 1);
182638889Sjdp      fprintf (e, " != %d", rt);
182738889Sjdp    }
182838889Sjdp
182938889Sjdp  if (res->coff_info.codepage != 0)
183038889Sjdp    fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
183138889Sjdp  if (res->coff_info.reserved != 0)
183238889Sjdp    fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
183338889Sjdp
183438889Sjdp  if (name != NULL)
183538889Sjdp    res_id_print (e, *name, 0);
183638889Sjdp  else
183738889Sjdp    fprintf (e, "??Unknown-Name??");
183838889Sjdp
183938889Sjdp  fprintf (e, " ");
184038889Sjdp  if (s != NULL)
184138889Sjdp    fprintf (e, "%s", s);
184238889Sjdp  else if (type != NULL)
184338889Sjdp    res_id_print (e, *type, 0);
184438889Sjdp  else
184538889Sjdp    fprintf (e, "??Unknown-Type??");
184638889Sjdp
184738889Sjdp  if (res->res_info.memflags != 0)
184838889Sjdp    {
184938889Sjdp      if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
185038889Sjdp	fprintf (e, " MOVEABLE");
185138889Sjdp      if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
185238889Sjdp	fprintf (e, " PURE");
185338889Sjdp      if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
185438889Sjdp	fprintf (e, " PRELOAD");
185538889Sjdp      if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
185638889Sjdp	fprintf (e, " DISCARDABLE");
185738889Sjdp    }
185838889Sjdp
185938889Sjdp  if (res->type == RES_TYPE_DIALOG)
186038889Sjdp    {
186138889Sjdp      fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
186238889Sjdp	       res->u.dialog->width, res->u.dialog->height);
186338889Sjdp      if (res->u.dialog->ex != NULL
186438889Sjdp	  && res->u.dialog->ex->help != 0)
186538889Sjdp	fprintf (e, ", %lu", res->u.dialog->ex->help);
186638889Sjdp    }
186738889Sjdp
186838889Sjdp  fprintf (e, "\n");
186938889Sjdp
187038889Sjdp  if ((res->res_info.language != 0 && res->res_info.language != *language)
187138889Sjdp      || res->res_info.characteristics != 0
187238889Sjdp      || res->res_info.version != 0)
187338889Sjdp    {
187438889Sjdp      int modifiers;
187538889Sjdp
187638889Sjdp      switch (res->type)
187738889Sjdp	{
187838889Sjdp	case RES_TYPE_ACCELERATOR:
187938889Sjdp	case RES_TYPE_DIALOG:
188038889Sjdp	case RES_TYPE_MENU:
188138889Sjdp	case RES_TYPE_RCDATA:
188238889Sjdp	case RES_TYPE_STRINGTABLE:
188338889Sjdp	  modifiers = 1;
188438889Sjdp	  break;
188538889Sjdp
188638889Sjdp	default:
188738889Sjdp	  modifiers = 0;
188838889Sjdp	  break;
188938889Sjdp	}
189038889Sjdp
189138889Sjdp      if (res->res_info.language != 0 && res->res_info.language != *language)
189238889Sjdp	fprintf (e, "%sLANGUAGE %d, %d\n",
189338889Sjdp		 modifiers ? "// " : "",
189489857Sobrien		 res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
189589857Sobrien		 (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
189638889Sjdp      if (res->res_info.characteristics != 0)
189738889Sjdp	fprintf (e, "%sCHARACTERISTICS %lu\n",
189838889Sjdp		 modifiers ? "// " : "",
189938889Sjdp		 res->res_info.characteristics);
190038889Sjdp      if (res->res_info.version != 0)
190138889Sjdp	fprintf (e, "%sVERSION %lu\n",
190238889Sjdp		 modifiers ? "// " : "",
190338889Sjdp		 res->res_info.version);
190438889Sjdp    }
190538889Sjdp
190638889Sjdp  switch (res->type)
190738889Sjdp    {
190838889Sjdp    default:
190938889Sjdp      abort ();
191038889Sjdp
191138889Sjdp    case RES_TYPE_ACCELERATOR:
191238889Sjdp      write_rc_accelerators (e, res->u.acc);
191338889Sjdp      break;
191438889Sjdp
191538889Sjdp    case RES_TYPE_CURSOR:
191638889Sjdp      write_rc_cursor (e, res->u.cursor);
191738889Sjdp      break;
191838889Sjdp
191938889Sjdp    case RES_TYPE_GROUP_CURSOR:
192038889Sjdp      write_rc_group_cursor (e, res->u.group_cursor);
192138889Sjdp      break;
192238889Sjdp
192338889Sjdp    case RES_TYPE_DIALOG:
192438889Sjdp      write_rc_dialog (e, res->u.dialog);
192538889Sjdp      break;
192638889Sjdp
192738889Sjdp    case RES_TYPE_FONTDIR:
192838889Sjdp      write_rc_fontdir (e, res->u.fontdir);
192938889Sjdp      break;
193038889Sjdp
193138889Sjdp    case RES_TYPE_GROUP_ICON:
193238889Sjdp      write_rc_group_icon (e, res->u.group_icon);
193338889Sjdp      break;
193438889Sjdp
193538889Sjdp    case RES_TYPE_MENU:
193638889Sjdp      write_rc_menu (e, res->u.menu, menuex);
193738889Sjdp      break;
193838889Sjdp
193938889Sjdp    case RES_TYPE_RCDATA:
194038889Sjdp      write_rc_rcdata (e, res->u.rcdata, 0);
194138889Sjdp      break;
194238889Sjdp
194338889Sjdp    case RES_TYPE_STRINGTABLE:
194438889Sjdp      write_rc_stringtable (e, name, res->u.stringtable);
194538889Sjdp      break;
194638889Sjdp
194738889Sjdp    case RES_TYPE_USERDATA:
194838889Sjdp      write_rc_rcdata (e, res->u.userdata, 0);
194938889Sjdp      break;
195038889Sjdp
195138889Sjdp    case RES_TYPE_VERSIONINFO:
195238889Sjdp      write_rc_versioninfo (e, res->u.versioninfo);
195338889Sjdp      break;
195438889Sjdp
195538889Sjdp    case RES_TYPE_BITMAP:
195638889Sjdp    case RES_TYPE_FONT:
195738889Sjdp    case RES_TYPE_ICON:
195838889Sjdp    case RES_TYPE_MESSAGETABLE:
195938889Sjdp      write_rc_filedata (e, res->u.data.length, res->u.data.data);
196038889Sjdp      break;
196138889Sjdp    }
196238889Sjdp}
196338889Sjdp
196438889Sjdp/* Write out accelerator information.  */
196538889Sjdp
196638889Sjdpstatic void
196738889Sjdpwrite_rc_accelerators (e, accelerators)
196838889Sjdp     FILE *e;
196938889Sjdp     const struct accelerator *accelerators;
197038889Sjdp{
197138889Sjdp  const struct accelerator *acc;
197238889Sjdp
197338889Sjdp  fprintf (e, "BEGIN\n");
197438889Sjdp  for (acc = accelerators; acc != NULL; acc = acc->next)
197538889Sjdp    {
197638889Sjdp      int printable;
197738889Sjdp
197838889Sjdp      fprintf (e, "  ");
197938889Sjdp
198038889Sjdp      if ((acc->key & 0x7f) == acc->key
198189857Sobrien	  && ISPRINT (acc->key)
198238889Sjdp	  && (acc->flags & ACC_VIRTKEY) == 0)
198338889Sjdp	{
198438889Sjdp	  fprintf (e, "\"%c\"", acc->key);
198538889Sjdp	  printable = 1;
198638889Sjdp	}
198738889Sjdp      else
198838889Sjdp	{
198938889Sjdp	  fprintf (e, "%d", acc->key);
199038889Sjdp	  printable = 0;
199138889Sjdp	}
199238889Sjdp
199338889Sjdp      fprintf (e, ", %d", acc->id);
199438889Sjdp
199538889Sjdp      if (! printable)
199638889Sjdp	{
199738889Sjdp	  if ((acc->flags & ACC_VIRTKEY) != 0)
199838889Sjdp	    fprintf (e, ", VIRTKEY");
199938889Sjdp	  else
200038889Sjdp	    fprintf (e, ", ASCII");
200138889Sjdp	}
200238889Sjdp
200338889Sjdp      if ((acc->flags & ACC_SHIFT) != 0)
200438889Sjdp	fprintf (e, ", SHIFT");
200538889Sjdp      if ((acc->flags & ACC_CONTROL) != 0)
200638889Sjdp	fprintf (e, ", CONTROL");
200738889Sjdp      if ((acc->flags & ACC_ALT) != 0)
200838889Sjdp	fprintf (e, ", ALT");
200938889Sjdp
201038889Sjdp      fprintf (e, "\n");
201138889Sjdp    }
201238889Sjdp
201338889Sjdp  fprintf (e, "END\n");
201438889Sjdp}
201538889Sjdp
201638889Sjdp/* Write out cursor information.  This would normally be in a separate
201738889Sjdp   file, which the rc file would include.  */
201838889Sjdp
201938889Sjdpstatic void
202038889Sjdpwrite_rc_cursor (e, cursor)
202138889Sjdp     FILE *e;
202238889Sjdp     const struct cursor *cursor;
202338889Sjdp{
202438889Sjdp  fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
202538889Sjdp	   cursor->yhotspot);
202638889Sjdp  write_rc_filedata (e, cursor->length, cursor->data);
202738889Sjdp}
202838889Sjdp
202938889Sjdp/* Write out group cursor data.  This would normally be built from the
203038889Sjdp   cursor data.  */
203138889Sjdp
203238889Sjdpstatic void
203338889Sjdpwrite_rc_group_cursor (e, group_cursor)
203438889Sjdp     FILE *e;
203538889Sjdp     const struct group_cursor *group_cursor;
203638889Sjdp{
203738889Sjdp  const struct group_cursor *gc;
203838889Sjdp
203938889Sjdp  for (gc = group_cursor; gc != NULL; gc = gc->next)
204038889Sjdp    {
204138889Sjdp      fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
204238889Sjdp	     gc->width, gc->height, gc->planes, gc->bits);
204338889Sjdp      fprintf (e, "// data bytes: %lu; index: %d\n",
204438889Sjdp	       gc->bytes, gc->index);
204538889Sjdp    }
204638889Sjdp}
204738889Sjdp
204838889Sjdp/* Write dialog data.  */
204938889Sjdp
205038889Sjdpstatic void
205138889Sjdpwrite_rc_dialog (e, dialog)
205238889Sjdp     FILE *e;
205338889Sjdp     const struct dialog *dialog;
205438889Sjdp{
205538889Sjdp  const struct dialog_control *control;
205638889Sjdp
205799461Sobrien  fprintf (e, "STYLE 0x%lx\n", dialog->style);
205899461Sobrien
205938889Sjdp  if (dialog->exstyle != 0)
206038889Sjdp    fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
206199461Sobrien
206238889Sjdp  if ((dialog->class.named && dialog->class.u.n.length > 0)
206338889Sjdp      || dialog->class.u.id != 0)
206438889Sjdp    {
206538889Sjdp      fprintf (e, "CLASS ");
206699461Sobrien      res_id_print (e, dialog->class, 1);
206738889Sjdp      fprintf (e, "\n");
206838889Sjdp    }
206999461Sobrien
207038889Sjdp  if (dialog->caption != NULL)
207138889Sjdp    {
207238889Sjdp      fprintf (e, "CAPTION \"");
207338889Sjdp      unicode_print (e, dialog->caption, -1);
207438889Sjdp      fprintf (e, "\"\n");
207538889Sjdp    }
207699461Sobrien
207738889Sjdp  if ((dialog->menu.named && dialog->menu.u.n.length > 0)
207838889Sjdp      || dialog->menu.u.id != 0)
207938889Sjdp    {
208038889Sjdp      fprintf (e, "MENU ");
208138889Sjdp      res_id_print (e, dialog->menu, 0);
208238889Sjdp      fprintf (e, "\n");
208338889Sjdp    }
208499461Sobrien
208538889Sjdp  if (dialog->font != NULL)
208638889Sjdp    {
208738889Sjdp      fprintf (e, "FONT %d, \"", dialog->pointsize);
208838889Sjdp      unicode_print (e, dialog->font, -1);
208938889Sjdp      fprintf (e, "\"");
209038889Sjdp      if (dialog->ex != NULL
209199461Sobrien	  && (dialog->ex->weight != 0
209299461Sobrien	      || dialog->ex->italic != 0
209399461Sobrien	      || dialog->ex->charset != 1))
209499461Sobrien	fprintf (e, ", %d, %d, %d",
209599461Sobrien		 dialog->ex->weight, dialog->ex->italic, dialog->ex->charset);
209638889Sjdp      fprintf (e, "\n");
209738889Sjdp    }
209838889Sjdp
209938889Sjdp  fprintf (e, "BEGIN\n");
210038889Sjdp
210138889Sjdp  for (control = dialog->controls; control != NULL; control = control->next)
210238889Sjdp    write_rc_dialog_control (e, control);
210338889Sjdp
210438889Sjdp  fprintf (e, "END\n");
210538889Sjdp}
210638889Sjdp
210738889Sjdp/* For each predefined control keyword, this table provides the class
210838889Sjdp   and the style.  */
210938889Sjdp
211038889Sjdpstruct control_info
211138889Sjdp{
211238889Sjdp  const char *name;
211338889Sjdp  unsigned short class;
211438889Sjdp  unsigned long style;
211538889Sjdp};
211638889Sjdp
211738889Sjdpstatic const struct control_info control_info[] =
211838889Sjdp{
211938889Sjdp  { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
212038889Sjdp  { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
212138889Sjdp  { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
212238889Sjdp  { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
212338889Sjdp  { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
212438889Sjdp  { "CTEXT", CTL_STATIC, SS_CENTER },
212538889Sjdp  { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
212638889Sjdp  { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
212738889Sjdp  { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
212838889Sjdp  { "ICON", CTL_STATIC, SS_ICON },
212938889Sjdp  { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
213038889Sjdp  { "LTEXT", CTL_STATIC, SS_LEFT },
213138889Sjdp  { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
213238889Sjdp  { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
213338889Sjdp  { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
213438889Sjdp  { "RTEXT", CTL_STATIC, SS_RIGHT },
213538889Sjdp  { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
213638889Sjdp  { "STATE3", CTL_BUTTON, BS_3STATE },
213738889Sjdp  /* It's important that USERBUTTON come after all the other button
213838889Sjdp     types, so that it won't be matched too early.  */
213938889Sjdp  { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
214038889Sjdp  { NULL, 0, 0 }
214138889Sjdp};
214238889Sjdp
214338889Sjdp/* Write a dialog control.  */
214438889Sjdp
214538889Sjdpstatic void
214638889Sjdpwrite_rc_dialog_control (e, control)
214738889Sjdp     FILE *e;
214838889Sjdp     const struct dialog_control *control;
214938889Sjdp{
215038889Sjdp  const struct control_info *ci;
215138889Sjdp
215238889Sjdp  fprintf (e, "  ");
215338889Sjdp
215438889Sjdp  if (control->class.named)
215538889Sjdp    ci = NULL;
215638889Sjdp  else
215738889Sjdp    {
215838889Sjdp      for (ci = control_info; ci->name != NULL; ++ci)
215938889Sjdp	if (ci->class == control->class.u.id
216038889Sjdp	    && (ci->style == (unsigned long) -1
216138889Sjdp		|| ci->style == (control->style & 0xff)))
216238889Sjdp	  break;
216338889Sjdp    }
216460484Sobrien  if (ci == NULL)
216560484Sobrien    fprintf (e, "CONTROL");
216660484Sobrien  else if (ci->name != NULL)
216738889Sjdp    fprintf (e, "%s", ci->name);
216838889Sjdp  else
216938889Sjdp    fprintf (e, "CONTROL");
2170104834Sobrien
217138889Sjdp  if (control->text.named || control->text.u.id != 0)
217238889Sjdp    {
217338889Sjdp      fprintf (e, " ");
217438889Sjdp      res_id_print (e, control->text, 1);
217538889Sjdp      fprintf (e, ",");
217638889Sjdp    }
217738889Sjdp
217838889Sjdp  fprintf (e, " %d, ", control->id);
217938889Sjdp
218060484Sobrien  if (ci == NULL)
218138889Sjdp    {
218260484Sobrien      if (control->class.named)
218360484Sobrien	fprintf (e, "\"");
218438889Sjdp      res_id_print (e, control->class, 0);
218560484Sobrien      if (control->class.named)
218660484Sobrien	fprintf (e, "\"");
218738889Sjdp      fprintf (e, ", 0x%lx, ", control->style);
218838889Sjdp    }
218938889Sjdp
219038889Sjdp  fprintf (e, "%d, %d", control->x, control->y);
219138889Sjdp
219238889Sjdp  if (control->style != SS_ICON
219338889Sjdp      || control->exstyle != 0
219438889Sjdp      || control->width != 0
219538889Sjdp      || control->height != 0
219638889Sjdp      || control->help != 0)
219738889Sjdp    {
219838889Sjdp      fprintf (e, ", %d, %d", control->width, control->height);
219938889Sjdp
220038889Sjdp      /* FIXME: We don't need to print the style if it is the default.
220138889Sjdp	 More importantly, in certain cases we actually need to turn
220238889Sjdp	 off parts of the forced style, by using NOT.  */
220338889Sjdp      fprintf (e, ", 0x%lx", control->style);
220438889Sjdp
220538889Sjdp      if (control->exstyle != 0 || control->help != 0)
220638889Sjdp	fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
220738889Sjdp    }
220838889Sjdp
220938889Sjdp  fprintf (e, "\n");
221038889Sjdp
221138889Sjdp  if (control->data != NULL)
221238889Sjdp    write_rc_rcdata (e, control->data, 2);
221338889Sjdp}
221438889Sjdp
221538889Sjdp/* Write out font directory data.  This would normally be built from
221638889Sjdp   the font data.  */
221738889Sjdp
221838889Sjdpstatic void
221938889Sjdpwrite_rc_fontdir (e, fontdir)
222038889Sjdp     FILE *e;
222138889Sjdp     const struct fontdir *fontdir;
222238889Sjdp{
222338889Sjdp  const struct fontdir *fc;
222438889Sjdp
222538889Sjdp  for (fc = fontdir; fc != NULL; fc = fc->next)
222638889Sjdp    {
222738889Sjdp      fprintf (e, "// Font index: %d\n", fc->index);
222838889Sjdp      write_rc_filedata (e, fc->length, fc->data);
222938889Sjdp    }
223038889Sjdp}
223138889Sjdp
223238889Sjdp/* Write out group icon data.  This would normally be built from the
223338889Sjdp   icon data.  */
223438889Sjdp
223538889Sjdpstatic void
223638889Sjdpwrite_rc_group_icon (e, group_icon)
223738889Sjdp     FILE *e;
223838889Sjdp     const struct group_icon *group_icon;
223938889Sjdp{
224038889Sjdp  const struct group_icon *gi;
224138889Sjdp
224238889Sjdp  for (gi = group_icon; gi != NULL; gi = gi->next)
224338889Sjdp    {
224438889Sjdp      fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
224538889Sjdp	       gi->width, gi->height, gi->colors, gi->planes, gi->bits);
224638889Sjdp      fprintf (e, "// data bytes: %lu; index: %d\n",
224738889Sjdp	       gi->bytes, gi->index);
224838889Sjdp    }
224938889Sjdp}
225038889Sjdp
225138889Sjdp/* Write out a menu resource.  */
225238889Sjdp
225338889Sjdpstatic void
225438889Sjdpwrite_rc_menu (e, menu, menuex)
225538889Sjdp     FILE *e;
225638889Sjdp     const struct menu *menu;
225738889Sjdp     int menuex;
225838889Sjdp{
225938889Sjdp  if (menu->help != 0)
226038889Sjdp    fprintf (e, "// Help ID: %lu\n", menu->help);
226138889Sjdp  write_rc_menuitems (e, menu->items, menuex, 0);
226238889Sjdp}
226338889Sjdp
226438889Sjdp/* Write out menuitems.  */
226538889Sjdp
226638889Sjdpstatic void
226738889Sjdpwrite_rc_menuitems (e, menuitems, menuex, ind)
226838889Sjdp     FILE *e;
226938889Sjdp     const struct menuitem *menuitems;
227038889Sjdp     int menuex;
227138889Sjdp     int ind;
227238889Sjdp{
227338889Sjdp  const struct menuitem *mi;
227438889Sjdp
227538889Sjdp  indent (e, ind);
227638889Sjdp  fprintf (e, "BEGIN\n");
227738889Sjdp
227838889Sjdp  for (mi = menuitems; mi != NULL; mi = mi->next)
227938889Sjdp    {
228038889Sjdp      indent (e, ind + 2);
228138889Sjdp
228238889Sjdp      if (mi->popup == NULL)
228338889Sjdp	fprintf (e, "MENUITEM");
228438889Sjdp      else
228538889Sjdp	fprintf (e, "POPUP");
228638889Sjdp
228738889Sjdp      if (! menuex
228838889Sjdp	  && mi->popup == NULL
228938889Sjdp	  && mi->text == NULL
229038889Sjdp	  && mi->type == 0
229138889Sjdp	  && mi->id == 0)
229238889Sjdp	{
229338889Sjdp	  fprintf (e, " SEPARATOR\n");
229438889Sjdp	  continue;
229538889Sjdp	}
229638889Sjdp
229738889Sjdp      if (mi->text == NULL)
229838889Sjdp	fprintf (e, " \"\"");
229938889Sjdp      else
230038889Sjdp	{
230138889Sjdp	  fprintf (e, " \"");
230238889Sjdp	  unicode_print (e, mi->text, -1);
230338889Sjdp	  fprintf (e, "\"");
230438889Sjdp	}
230538889Sjdp
230638889Sjdp      if (! menuex)
230738889Sjdp	{
230838889Sjdp	  if (mi->popup == NULL)
230938889Sjdp	    fprintf (e, ", %d", mi->id);
231038889Sjdp
231138889Sjdp	  if ((mi->type & MENUITEM_CHECKED) != 0)
231238889Sjdp	    fprintf (e, ", CHECKED");
231338889Sjdp	  if ((mi->type & MENUITEM_GRAYED) != 0)
231438889Sjdp	    fprintf (e, ", GRAYED");
231538889Sjdp	  if ((mi->type & MENUITEM_HELP) != 0)
231638889Sjdp	    fprintf (e, ", HELP");
231738889Sjdp	  if ((mi->type & MENUITEM_INACTIVE) != 0)
231838889Sjdp	    fprintf (e, ", INACTIVE");
231938889Sjdp	  if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
232038889Sjdp	    fprintf (e, ", MENUBARBREAK");
232138889Sjdp	  if ((mi->type & MENUITEM_MENUBREAK) != 0)
232238889Sjdp	    fprintf (e, ", MENUBREAK");
232338889Sjdp	}
232438889Sjdp      else
232538889Sjdp	{
232638889Sjdp	  if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
232738889Sjdp	    {
232838889Sjdp	      fprintf (e, ", %d", mi->id);
232938889Sjdp	      if (mi->type != 0 || mi->state != 0 || mi->help != 0)
233038889Sjdp		{
233138889Sjdp		  fprintf (e, ", %lu", mi->type);
233238889Sjdp		  if (mi->state != 0 || mi->help != 0)
233338889Sjdp		    {
233438889Sjdp		      fprintf (e, ", %lu", mi->state);
233538889Sjdp		      if (mi->help != 0)
233638889Sjdp			fprintf (e, ", %lu", mi->help);
233738889Sjdp		    }
233838889Sjdp		}
233938889Sjdp	    }
234038889Sjdp	}
234138889Sjdp
234238889Sjdp      fprintf (e, "\n");
234338889Sjdp
234438889Sjdp      if (mi->popup != NULL)
234538889Sjdp	write_rc_menuitems (e, mi->popup, menuex, ind + 2);
234638889Sjdp    }
234738889Sjdp
234838889Sjdp  indent (e, ind);
234938889Sjdp  fprintf (e, "END\n");
235038889Sjdp}
235138889Sjdp
235238889Sjdp/* Write out an rcdata resource.  This is also used for other types of
235338889Sjdp   resources that need to print arbitrary data.  */
235438889Sjdp
235538889Sjdpstatic void
235638889Sjdpwrite_rc_rcdata (e, rcdata, ind)
235738889Sjdp     FILE *e;
235838889Sjdp     const struct rcdata_item *rcdata;
235938889Sjdp     int ind;
236038889Sjdp{
236138889Sjdp  const struct rcdata_item *ri;
236238889Sjdp
236338889Sjdp  indent (e, ind);
236438889Sjdp  fprintf (e, "BEGIN\n");
236538889Sjdp
236638889Sjdp  for (ri = rcdata; ri != NULL; ri = ri->next)
236738889Sjdp    {
236838889Sjdp      if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
236938889Sjdp	continue;
237038889Sjdp
237138889Sjdp      indent (e, ind + 2);
237238889Sjdp
237338889Sjdp      switch (ri->type)
237438889Sjdp	{
237538889Sjdp	default:
237638889Sjdp	  abort ();
237738889Sjdp
237838889Sjdp	case RCDATA_WORD:
237938889Sjdp	  fprintf (e, "%d", ri->u.word);
238038889Sjdp	  break;
238138889Sjdp
238238889Sjdp	case RCDATA_DWORD:
238338889Sjdp	  fprintf (e, "%luL", ri->u.dword);
238438889Sjdp	  break;
238538889Sjdp
238638889Sjdp	case RCDATA_STRING:
238738889Sjdp	  {
238838889Sjdp	    const char *s;
238938889Sjdp	    unsigned long i;
239038889Sjdp
239138889Sjdp	    fprintf (e, "\"");
239238889Sjdp	    s = ri->u.string.s;
239338889Sjdp	    for (i = 0; i < ri->u.string.length; i++)
239438889Sjdp	      {
239589857Sobrien		if (ISPRINT (*s))
239638889Sjdp		  putc (*s, e);
239738889Sjdp		else
239838889Sjdp		  fprintf (e, "\\%03o", *s);
239938889Sjdp	      }
240038889Sjdp	    fprintf (e, "\"");
240138889Sjdp	    break;
240238889Sjdp	  }
240338889Sjdp
240438889Sjdp	case RCDATA_WSTRING:
240538889Sjdp	  fprintf (e, "L\"");
240638889Sjdp	  unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
240738889Sjdp	  fprintf (e, "\"");
240838889Sjdp	  break;
240938889Sjdp
241038889Sjdp	case RCDATA_BUFFER:
241138889Sjdp	  {
241238889Sjdp	    unsigned long i;
241338889Sjdp	    int first;
241438889Sjdp
241538889Sjdp	    /* Assume little endian data.  */
241638889Sjdp
241738889Sjdp	    first = 1;
241838889Sjdp	    for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
241938889Sjdp	      {
242038889Sjdp		unsigned long l;
242160484Sobrien		int j;
242238889Sjdp
242360484Sobrien		if (! first)
242460484Sobrien		  indent (e, ind + 2);
242538889Sjdp		l = ((((((ri->u.buffer.data[i + 3] << 8)
242638889Sjdp			 | ri->u.buffer.data[i + 2]) << 8)
242738889Sjdp		       | ri->u.buffer.data[i + 1]) << 8)
242838889Sjdp		     | ri->u.buffer.data[i]);
242960484Sobrien		fprintf (e, "%luL", l);
243060484Sobrien		if (i + 4 < ri->u.buffer.length || ri->next != NULL)
243160484Sobrien		  fprintf (e, ",");
243260484Sobrien		for (j = 0; j < 4; ++j)
243389857Sobrien		  if (! ISPRINT (ri->u.buffer.data[i + j])
243460484Sobrien		      && ri->u.buffer.data[i + j] != 0)
243560484Sobrien		    break;
243660484Sobrien		if (j >= 4)
243738889Sjdp		  {
243860484Sobrien		    fprintf (e, "\t// ");
243960484Sobrien		    for (j = 0; j < 4; ++j)
244060484Sobrien		      {
244189857Sobrien			if (! ISPRINT (ri->u.buffer.data[i + j]))
244260484Sobrien			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
244360484Sobrien			else
244460484Sobrien			  {
244560484Sobrien			    if (ri->u.buffer.data[i + j] == '\\')
244660484Sobrien			      fprintf (e, "\\");
244760484Sobrien			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
244860484Sobrien			  }
244960484Sobrien		      }
245038889Sjdp		  }
245160484Sobrien		fprintf (e, "\n");
245260484Sobrien		first = 0;
245338889Sjdp	      }
245438889Sjdp
245538889Sjdp	    if (i + 1 < ri->u.buffer.length)
245638889Sjdp	      {
245760484Sobrien		int s;
245860484Sobrien		int j;
245938889Sjdp
246060484Sobrien		if (! first)
246160484Sobrien		  indent (e, ind + 2);
246260484Sobrien		s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
246360484Sobrien		fprintf (e, "%d", s);
246460484Sobrien		if (i + 2 < ri->u.buffer.length || ri->next != NULL)
246560484Sobrien		  fprintf (e, ",");
246660484Sobrien		for (j = 0; j < 2; ++j)
246789857Sobrien		  if (! ISPRINT (ri->u.buffer.data[i + j])
246860484Sobrien		      && ri->u.buffer.data[i + j] != 0)
246960484Sobrien		    break;
247060484Sobrien		if (j >= 2)
247138889Sjdp		  {
247260484Sobrien		    fprintf (e, "\t// ");
247360484Sobrien		    for (j = 0; j < 2; ++j)
247460484Sobrien		      {
247589857Sobrien			if (! ISPRINT (ri->u.buffer.data[i + j]))
247660484Sobrien			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
247760484Sobrien			else
247860484Sobrien			  {
247960484Sobrien			    if (ri->u.buffer.data[i + j] == '\\')
248060484Sobrien			      fprintf (e, "\\");
248160484Sobrien			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
248260484Sobrien			  }
248360484Sobrien		      }
248438889Sjdp		  }
248560484Sobrien		fprintf (e, "\n");
248638889Sjdp		i += 2;
248760484Sobrien		first = 0;
248838889Sjdp	      }
248938889Sjdp
249038889Sjdp	    if (i < ri->u.buffer.length)
249138889Sjdp	      {
249260484Sobrien		if (! first)
249360484Sobrien		  indent (e, ind + 2);
249438889Sjdp		if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
249589857Sobrien		    && ISPRINT (ri->u.buffer.data[i]))
249638889Sjdp		  fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
249738889Sjdp		else
249860484Sobrien		  fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
249960484Sobrien		if (ri->next != NULL)
250060484Sobrien		  fprintf (e, ",");
250160484Sobrien		fprintf (e, "\n");
250260484Sobrien		first = 0;
250338889Sjdp	      }
250438889Sjdp
250538889Sjdp	    break;
250638889Sjdp	  }
250738889Sjdp	}
250838889Sjdp
250960484Sobrien      if (ri->type != RCDATA_BUFFER)
251060484Sobrien	{
251160484Sobrien	  if (ri->next != NULL)
251260484Sobrien	    fprintf (e, ",");
251360484Sobrien	  fprintf (e, "\n");
251460484Sobrien	}
251538889Sjdp    }
251638889Sjdp
251738889Sjdp  indent (e, ind);
251838889Sjdp  fprintf (e, "END\n");
251938889Sjdp}
252038889Sjdp
252138889Sjdp/* Write out a stringtable resource.  */
252238889Sjdp
252338889Sjdpstatic void
252438889Sjdpwrite_rc_stringtable (e, name, stringtable)
252538889Sjdp     FILE *e;
252638889Sjdp     const struct res_id *name;
252738889Sjdp     const struct stringtable *stringtable;
252838889Sjdp{
252938889Sjdp  unsigned long offset;
253038889Sjdp  int i;
253138889Sjdp
253238889Sjdp  if (name != NULL && ! name->named)
253338889Sjdp    offset = (name->u.id - 1) << 4;
253438889Sjdp  else
253538889Sjdp    {
253638889Sjdp      fprintf (e, "// %s string table name\n",
253738889Sjdp	       name == NULL ? "Missing" : "Invalid");
253838889Sjdp      offset = 0;
253938889Sjdp    }
254038889Sjdp
254138889Sjdp  fprintf (e, "BEGIN\n");
254238889Sjdp
254338889Sjdp  for (i = 0; i < 16; i++)
254438889Sjdp    {
254538889Sjdp      if (stringtable->strings[i].length != 0)
254638889Sjdp	{
254738889Sjdp	  fprintf (e, "  %lu, \"", offset + i);
254838889Sjdp	  unicode_print (e, stringtable->strings[i].string,
254938889Sjdp			 stringtable->strings[i].length);
255038889Sjdp	  fprintf (e, "\"\n");
255138889Sjdp	}
255238889Sjdp    }
255338889Sjdp
255438889Sjdp  fprintf (e, "END\n");
255538889Sjdp}
255638889Sjdp
255738889Sjdp/* Write out a versioninfo resource.  */
255838889Sjdp
255938889Sjdpstatic void
256038889Sjdpwrite_rc_versioninfo (e, versioninfo)
256138889Sjdp     FILE *e;
256238889Sjdp     const struct versioninfo *versioninfo;
256338889Sjdp{
256438889Sjdp  const struct fixed_versioninfo *f;
256538889Sjdp  const struct ver_info *vi;
256638889Sjdp
256738889Sjdp  f = versioninfo->fixed;
256838889Sjdp  if (f->file_version_ms != 0 || f->file_version_ls != 0)
256938889Sjdp    fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
257038889Sjdp	     (f->file_version_ms >> 16) & 0xffff,
257138889Sjdp	     f->file_version_ms & 0xffff,
257238889Sjdp	     (f->file_version_ls >> 16) & 0xffff,
257338889Sjdp	     f->file_version_ls & 0xffff);
257438889Sjdp  if (f->product_version_ms != 0 || f->product_version_ls != 0)
257538889Sjdp    fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
257638889Sjdp	     (f->product_version_ms >> 16) & 0xffff,
257738889Sjdp	     f->product_version_ms & 0xffff,
257838889Sjdp	     (f->product_version_ls >> 16) & 0xffff,
257938889Sjdp	     f->product_version_ls & 0xffff);
258038889Sjdp  if (f->file_flags_mask != 0)
258138889Sjdp    fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
258238889Sjdp  if (f->file_flags != 0)
258338889Sjdp    fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
258438889Sjdp  if (f->file_os != 0)
258538889Sjdp    fprintf (e, " FILEOS 0x%lx\n", f->file_os);
258638889Sjdp  if (f->file_type != 0)
258738889Sjdp    fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
258838889Sjdp  if (f->file_subtype != 0)
258938889Sjdp    fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
259038889Sjdp  if (f->file_date_ms != 0 || f->file_date_ls != 0)
259138889Sjdp    fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
259238889Sjdp
259338889Sjdp  fprintf (e, "BEGIN\n");
259438889Sjdp
259538889Sjdp  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
259638889Sjdp    {
259738889Sjdp      switch (vi->type)
259838889Sjdp	{
259938889Sjdp	case VERINFO_STRING:
260038889Sjdp	  {
260138889Sjdp	    const struct ver_stringinfo *vs;
260238889Sjdp
260338889Sjdp	    fprintf (e, "  BLOCK \"StringFileInfo\"\n");
260438889Sjdp	    fprintf (e, "  BEGIN\n");
260538889Sjdp	    fprintf (e, "    BLOCK \"");
260638889Sjdp	    unicode_print (e, vi->u.string.language, -1);
260738889Sjdp	    fprintf (e, "\"\n");
260838889Sjdp	    fprintf (e, "    BEGIN\n");
260938889Sjdp
261038889Sjdp	    for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
261138889Sjdp	      {
261238889Sjdp		fprintf (e, "      VALUE \"");
261338889Sjdp		unicode_print (e, vs->key, -1);
261438889Sjdp		fprintf (e, "\", \"");
261538889Sjdp		unicode_print (e, vs->value, -1);
261638889Sjdp		fprintf (e, "\"\n");
261738889Sjdp	      }
261838889Sjdp
261938889Sjdp	    fprintf (e, "    END\n");
262038889Sjdp	    fprintf (e, "  END\n");
262138889Sjdp	    break;
262238889Sjdp	  }
262338889Sjdp
262438889Sjdp	case VERINFO_VAR:
262538889Sjdp	  {
262638889Sjdp	    const struct ver_varinfo *vv;
262738889Sjdp
262838889Sjdp	    fprintf (e, "  BLOCK \"VarFileInfo\"\n");
262938889Sjdp	    fprintf (e, "  BEGIN\n");
263038889Sjdp	    fprintf (e, "    VALUE \"");
263138889Sjdp	    unicode_print (e, vi->u.var.key, -1);
263238889Sjdp	    fprintf (e, "\"");
263338889Sjdp
263438889Sjdp	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
263538889Sjdp	      fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
263638889Sjdp		       vv->charset);
263738889Sjdp
263838889Sjdp	    fprintf (e, "\n  END\n");
263938889Sjdp
264038889Sjdp	    break;
264138889Sjdp	  }
264238889Sjdp	}
264338889Sjdp    }
264438889Sjdp
264538889Sjdp  fprintf (e, "END\n");
264638889Sjdp}
264738889Sjdp
264838889Sjdp/* Write out data which would normally be read from a file.  */
264938889Sjdp
265038889Sjdpstatic void
265138889Sjdpwrite_rc_filedata (e, length, data)
265238889Sjdp     FILE *e;
265338889Sjdp     unsigned long length;
265438889Sjdp     const unsigned char *data;
265538889Sjdp{
265638889Sjdp  unsigned long i;
265738889Sjdp
265838889Sjdp  for (i = 0; i + 15 < length; i += 16)
265938889Sjdp    {
266038889Sjdp      fprintf (e, "// %4lx: ", i);
266138889Sjdp      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
266238889Sjdp	       data[i + 0], data[i + 1], data[i + 2], data[i + 3],
266338889Sjdp	       data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
266438889Sjdp      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
266538889Sjdp	       data[i +  8], data[i +  9], data[i + 10], data[i + 11],
266638889Sjdp	       data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
266738889Sjdp    }
266838889Sjdp
266938889Sjdp  if (i < length)
267038889Sjdp    {
267138889Sjdp      fprintf (e, "// %4lx:", i);
267238889Sjdp      while (i < length)
267338889Sjdp	{
267438889Sjdp	  fprintf (e, " %02x", data[i]);
267538889Sjdp	  ++i;
267638889Sjdp	}
267738889Sjdp      fprintf (e, "\n");
267838889Sjdp    }
267938889Sjdp}
2680