resrc.c revision 130561
138889Sjdp/* resrc.c -- read and write Windows rc files.
2130561Sobrien   Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 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
164130561Sobrienstatic int run_cmd (char *, const char *);
165130561Sobrienstatic FILE *open_input_stream (char *);
166130561Sobrienstatic FILE *look_for_default
167130561Sobrien  (char *, const char *, int, const char *, const char *);
168130561Sobrienstatic void close_input_stream (void);
169130561Sobrienstatic void unexpected_eof (const char *);
170130561Sobrienstatic int get_word (FILE *, const char *);
171130561Sobrienstatic unsigned long get_long (FILE *, const char *);
172130561Sobrienstatic void get_data (FILE *, unsigned char *, unsigned long, const char *);
173130561Sobrienstatic void define_fontdirs (void);
17438889Sjdp
17599461Sobrien/* Run `cmd' and redirect the output to `redir'.  */
17660484Sobrien
17760484Sobrienstatic int
178130561Sobrienrun_cmd (char *cmd, const char *redir)
17960484Sobrien{
18060484Sobrien  char *s;
18160484Sobrien  int pid, wait_status, retcode;
18260484Sobrien  int i;
18360484Sobrien  const char **argv;
18460484Sobrien  char *errmsg_fmt, *errmsg_arg;
18560484Sobrien  char *temp_base = choose_temp_base ();
18660484Sobrien  int in_quote;
18760484Sobrien  char sep;
18860484Sobrien  int redir_handle = -1;
18960484Sobrien  int stdout_save = -1;
19060484Sobrien
19160484Sobrien  /* Count the args.  */
19260484Sobrien  i = 0;
193104834Sobrien
19460484Sobrien  for (s = cmd; *s; s++)
19560484Sobrien    if (*s == ' ')
19660484Sobrien      i++;
197104834Sobrien
19860484Sobrien  i++;
19960484Sobrien  argv = alloca (sizeof (char *) * (i + 3));
20060484Sobrien  i = 0;
20160484Sobrien  s = cmd;
202104834Sobrien
20360484Sobrien  while (1)
20460484Sobrien    {
20560484Sobrien      while (*s == ' ' && *s != 0)
20660484Sobrien	s++;
207104834Sobrien
20860484Sobrien      if (*s == 0)
20960484Sobrien	break;
210104834Sobrien
21160484Sobrien      in_quote = (*s == '\'' || *s == '"');
21260484Sobrien      sep = (in_quote) ? *s++ : ' ';
21360484Sobrien      argv[i++] = s;
214104834Sobrien
21560484Sobrien      while (*s != sep && *s != 0)
21660484Sobrien	s++;
217104834Sobrien
21860484Sobrien      if (*s == 0)
21960484Sobrien	break;
220104834Sobrien
22160484Sobrien      *s++ = 0;
222104834Sobrien
22360484Sobrien      if (in_quote)
224104834Sobrien	s++;
22560484Sobrien    }
22660484Sobrien  argv[i++] = NULL;
22760484Sobrien
22860484Sobrien  /* Setup the redirection.  We can't use the usual fork/exec and redirect
22960484Sobrien     since we may be running on non-POSIX Windows host.  */
23060484Sobrien
23160484Sobrien  fflush (stdout);
23260484Sobrien  fflush (stderr);
23360484Sobrien
23460484Sobrien  /* Open temporary output file.  */
23560484Sobrien  redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
23660484Sobrien  if (redir_handle == -1)
237104834Sobrien    fatal (_("can't open temporary file `%s': %s"), redir,
238104834Sobrien	   strerror (errno));
23960484Sobrien
24060484Sobrien  /* Duplicate the stdout file handle so it can be restored later.  */
24160484Sobrien  stdout_save = dup (STDOUT_FILENO);
24260484Sobrien  if (stdout_save == -1)
24360484Sobrien    fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
24460484Sobrien
24560484Sobrien  /* Redirect stdout to our output file.  */
24660484Sobrien  dup2 (redir_handle, STDOUT_FILENO);
24760484Sobrien
24860484Sobrien  pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
24960484Sobrien		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
25060484Sobrien
25160484Sobrien  /* Restore stdout to its previous setting.  */
25260484Sobrien  dup2 (stdout_save, STDOUT_FILENO);
25360484Sobrien
254130561Sobrien  /* Close response file.  */
25560484Sobrien  close (redir_handle);
25660484Sobrien
25760484Sobrien  if (pid == -1)
25860484Sobrien    {
25960484Sobrien      fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
26060484Sobrien      return 1;
26160484Sobrien    }
26260484Sobrien
26360484Sobrien  retcode = 0;
26460484Sobrien  pid = pwait (pid, &wait_status, 0);
265104834Sobrien
26660484Sobrien  if (pid == -1)
26760484Sobrien    {
26860484Sobrien      fatal (_("wait: %s"), strerror (errno));
26960484Sobrien      retcode = 1;
27060484Sobrien    }
27160484Sobrien  else if (WIFSIGNALED (wait_status))
27260484Sobrien    {
27360484Sobrien      fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
27460484Sobrien      retcode = 1;
27560484Sobrien    }
27660484Sobrien  else if (WIFEXITED (wait_status))
27760484Sobrien    {
27860484Sobrien      if (WEXITSTATUS (wait_status) != 0)
27960484Sobrien	{
280104834Sobrien	  fatal (_("%s exited with status %d"), cmd,
28160484Sobrien	         WEXITSTATUS (wait_status));
28260484Sobrien	  retcode = 1;
28360484Sobrien	}
28460484Sobrien    }
28560484Sobrien  else
28660484Sobrien    retcode = 1;
287104834Sobrien
28860484Sobrien  return retcode;
28960484Sobrien}
29060484Sobrien
29160484Sobrienstatic FILE *
292130561Sobrienopen_input_stream (char *cmd)
29360484Sobrien{
29460484Sobrien  if (istream_type == ISTREAM_FILE)
29560484Sobrien    {
29660484Sobrien      char *fileprefix;
29760484Sobrien
29860484Sobrien      fileprefix = choose_temp_base ();
29960484Sobrien      cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
30060484Sobrien      sprintf (cpp_temp_file, "%s.irc", fileprefix);
30160484Sobrien      free (fileprefix);
30260484Sobrien
30360484Sobrien      if (run_cmd (cmd, cpp_temp_file))
30460484Sobrien	fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
30560484Sobrien
30660484Sobrien      cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
30760484Sobrien      if (cpp_pipe == NULL)
308104834Sobrien	fatal (_("can't open temporary file `%s': %s"),
30960484Sobrien	       cpp_temp_file, strerror (errno));
310104834Sobrien
31160484Sobrien      if (verbose)
312104834Sobrien	fprintf (stderr,
31360484Sobrien	         _("Using temporary file `%s' to read preprocessor output\n"),
31460484Sobrien		 cpp_temp_file);
31560484Sobrien    }
31660484Sobrien  else
31760484Sobrien    {
31860484Sobrien      cpp_pipe = popen (cmd, FOPEN_RT);
31960484Sobrien      if (cpp_pipe == NULL)
320104834Sobrien	fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
32160484Sobrien      if (verbose)
32260484Sobrien	fprintf (stderr, _("Using popen to read preprocessor output\n"));
32360484Sobrien    }
32460484Sobrien
32560484Sobrien  xatexit (close_input_stream);
32660484Sobrien  return cpp_pipe;
32760484Sobrien}
32860484Sobrien
32960484Sobrien/* look for the preprocessor program */
33060484Sobrien
33160484Sobrienstatic FILE *
332130561Sobrienlook_for_default (char *cmd, const char *prefix, int end_prefix,
333130561Sobrien		  const char *preprocargs, const char *filename)
33460484Sobrien{
33560484Sobrien  char *space;
33660484Sobrien  int found;
33760484Sobrien  struct stat s;
33860484Sobrien
33960484Sobrien  strcpy (cmd, prefix);
34060484Sobrien
34160484Sobrien  sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
34260484Sobrien  space = strchr (cmd + end_prefix, ' ');
34360484Sobrien  if (space)
34460484Sobrien    *space = 0;
34560484Sobrien
34660484Sobrien  if (
34760484Sobrien#if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
34860484Sobrien      strchr (cmd, '\\') ||
34960484Sobrien#endif
35060484Sobrien      strchr (cmd, '/'))
35160484Sobrien    {
35260484Sobrien      found = (stat (cmd, &s) == 0
35360484Sobrien#ifdef HAVE_EXECUTABLE_SUFFIX
35460484Sobrien	       || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
35560484Sobrien#endif
35660484Sobrien	       );
35760484Sobrien
35860484Sobrien      if (! found)
35960484Sobrien	{
36060484Sobrien	  if (verbose)
36160484Sobrien	    fprintf (stderr, _("Tried `%s'\n"), cmd);
36260484Sobrien	  return NULL;
36360484Sobrien	}
36460484Sobrien    }
36560484Sobrien
36660484Sobrien  strcpy (cmd, prefix);
36760484Sobrien
36860484Sobrien  sprintf (cmd + end_prefix, "%s %s %s",
36960484Sobrien	   DEFAULT_PREPROCESSOR, preprocargs, filename);
37060484Sobrien
37160484Sobrien  if (verbose)
37260484Sobrien    fprintf (stderr, _("Using `%s'\n"), cmd);
37360484Sobrien
37460484Sobrien  cpp_pipe = open_input_stream (cmd);
37560484Sobrien  return cpp_pipe;
37660484Sobrien}
37760484Sobrien
37838889Sjdp/* Read an rc file.  */
37938889Sjdp
38038889Sjdpstruct res_directory *
381130561Sobrienread_rc_file (const char *filename, const char *preprocessor,
382130561Sobrien	      const char *preprocargs, int language, int use_temp_file)
38338889Sjdp{
38438889Sjdp  char *cmd;
38538889Sjdp
38660484Sobrien  istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
38738889Sjdp
38838889Sjdp  if (preprocargs == NULL)
38938889Sjdp    preprocargs = "";
39038889Sjdp  if (filename == NULL)
39138889Sjdp    filename = "-";
39238889Sjdp
39360484Sobrien  if (preprocessor)
39460484Sobrien    {
39560484Sobrien      cmd = xmalloc (strlen (preprocessor)
39660484Sobrien		     + strlen (preprocargs)
39760484Sobrien		     + strlen (filename)
39860484Sobrien		     + 10);
39960484Sobrien      sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
40038889Sjdp
40160484Sobrien      cpp_pipe = open_input_stream (cmd);
40260484Sobrien    }
40360484Sobrien  else
40460484Sobrien    {
40560484Sobrien      char *dash, *slash, *cp;
40660484Sobrien
40760484Sobrien      preprocessor = DEFAULT_PREPROCESSOR;
40860484Sobrien
40960484Sobrien      cmd = xmalloc (strlen (program_name)
41060484Sobrien		     + strlen (preprocessor)
41160484Sobrien		     + strlen (preprocargs)
41260484Sobrien		     + strlen (filename)
41360484Sobrien#ifdef HAVE_EXECUTABLE_SUFFIX
41460484Sobrien		     + strlen (EXECUTABLE_SUFFIX)
41560484Sobrien#endif
41660484Sobrien		     + 10);
41760484Sobrien
41860484Sobrien
41960484Sobrien      dash = slash = 0;
42060484Sobrien      for (cp = program_name; *cp; cp++)
42160484Sobrien	{
42260484Sobrien	  if (*cp == '-')
42360484Sobrien	    dash = cp;
42460484Sobrien	  if (
42560484Sobrien#if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
42660484Sobrien	      *cp == ':' || *cp == '\\' ||
42760484Sobrien#endif
42860484Sobrien	      *cp == '/')
42960484Sobrien	    {
43060484Sobrien	      slash = cp;
43160484Sobrien	      dash = 0;
43260484Sobrien	    }
43360484Sobrien	}
43460484Sobrien
43560484Sobrien      cpp_pipe = 0;
43660484Sobrien
43760484Sobrien      if (dash)
43860484Sobrien	{
43960484Sobrien	  /* First, try looking for a prefixed gcc in the windres
44060484Sobrien	     directory, with the same prefix as windres */
44160484Sobrien
44260484Sobrien	  cpp_pipe = look_for_default (cmd, program_name, dash-program_name+1,
44360484Sobrien				       preprocargs, filename);
44460484Sobrien	}
44560484Sobrien
44660484Sobrien      if (slash && !cpp_pipe)
44760484Sobrien	{
44860484Sobrien	  /* Next, try looking for a gcc in the same directory as
44960484Sobrien             that windres */
45060484Sobrien
45160484Sobrien	  cpp_pipe = look_for_default (cmd, program_name, slash-program_name+1,
45260484Sobrien				       preprocargs, filename);
45360484Sobrien	}
45460484Sobrien
45560484Sobrien      if (!cpp_pipe)
45660484Sobrien	{
45760484Sobrien	  /* Sigh, try the default */
45860484Sobrien
45960484Sobrien	  cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
46060484Sobrien	}
46160484Sobrien
46260484Sobrien    }
463104834Sobrien
46438889Sjdp  free (cmd);
46538889Sjdp
46638889Sjdp  rc_filename = xstrdup (filename);
46738889Sjdp  rc_lineno = 1;
46838889Sjdp  if (language != -1)
46938889Sjdp    rcparse_set_language (language);
47038889Sjdp  yyin = cpp_pipe;
47138889Sjdp  yyparse ();
47299461Sobrien  rcparse_discard_strings ();
47338889Sjdp
47460484Sobrien  close_input_stream ();
475104834Sobrien
47638889Sjdp  if (fontdirs != NULL)
47738889Sjdp    define_fontdirs ();
47838889Sjdp
47938889Sjdp  free (rc_filename);
48038889Sjdp  rc_filename = NULL;
48138889Sjdp
48238889Sjdp  return resources;
48338889Sjdp}
48438889Sjdp
48560484Sobrien/* Close the input stream if it is open.  */
48638889Sjdp
48760484Sobrienstatic void
488130561Sobrienclose_input_stream (void)
48938889Sjdp{
49060484Sobrien  if (istream_type == ISTREAM_FILE)
49160484Sobrien    {
49260484Sobrien      if (cpp_pipe != NULL)
49360484Sobrien	fclose (cpp_pipe);
49460484Sobrien
49560484Sobrien      if (cpp_temp_file != NULL)
49660484Sobrien	{
49760484Sobrien	  int errno_save = errno;
498104834Sobrien
49960484Sobrien	  unlink (cpp_temp_file);
50060484Sobrien	  errno = errno_save;
50160484Sobrien	  free (cpp_temp_file);
50260484Sobrien	}
50360484Sobrien    }
50460484Sobrien  else
50560484Sobrien    {
50660484Sobrien      if (cpp_pipe != NULL)
50760484Sobrien	pclose (cpp_pipe);
50860484Sobrien    }
50960484Sobrien
51099461Sobrien  /* Since this is also run via xatexit, safeguard.  */
51160484Sobrien  cpp_pipe = NULL;
51260484Sobrien  cpp_temp_file = NULL;
51338889Sjdp}
51438889Sjdp
51538889Sjdp/* Report an error while reading an rc file.  */
51638889Sjdp
51738889Sjdpvoid
518130561Sobrienyyerror (const char *msg)
51938889Sjdp{
52038889Sjdp  fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
52138889Sjdp}
52238889Sjdp
52338889Sjdp/* Issue a warning while reading an rc file.  */
52438889Sjdp
52538889Sjdpvoid
526130561Sobrienrcparse_warning (const char *msg)
52738889Sjdp{
52860484Sobrien  fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
52938889Sjdp}
53038889Sjdp
53138889Sjdp/* Die if we get an unexpected end of file.  */
53238889Sjdp
53338889Sjdpstatic void
534130561Sobrienunexpected_eof (const char *msg)
53538889Sjdp{
53660484Sobrien  fatal (_("%s: unexpected EOF"), msg);
53738889Sjdp}
53838889Sjdp
53938889Sjdp/* Read a 16 bit word from a file.  The data is assumed to be little
54038889Sjdp   endian.  */
54138889Sjdp
54238889Sjdpstatic int
543130561Sobrienget_word (FILE *e, const char *msg)
54438889Sjdp{
54538889Sjdp  int b1, b2;
54638889Sjdp
54738889Sjdp  b1 = getc (e);
54838889Sjdp  b2 = getc (e);
54938889Sjdp  if (feof (e))
55038889Sjdp    unexpected_eof (msg);
55138889Sjdp  return ((b2 & 0xff) << 8) | (b1 & 0xff);
55238889Sjdp}
55338889Sjdp
55438889Sjdp/* Read a 32 bit word from a file.  The data is assumed to be little
55538889Sjdp   endian.  */
55638889Sjdp
55738889Sjdpstatic unsigned long
558130561Sobrienget_long (FILE *e, const char *msg)
55938889Sjdp{
56038889Sjdp  int b1, b2, b3, b4;
56138889Sjdp
56238889Sjdp  b1 = getc (e);
56338889Sjdp  b2 = getc (e);
56438889Sjdp  b3 = getc (e);
56538889Sjdp  b4 = getc (e);
56638889Sjdp  if (feof (e))
56738889Sjdp    unexpected_eof (msg);
56838889Sjdp  return (((((((b4 & 0xff) << 8)
56938889Sjdp	      | (b3 & 0xff)) << 8)
57038889Sjdp	    | (b2 & 0xff)) << 8)
57138889Sjdp	  | (b1 & 0xff));
57238889Sjdp}
57338889Sjdp
57438889Sjdp/* Read data from a file.  This is a wrapper to do error checking.  */
57538889Sjdp
57638889Sjdpstatic void
577130561Sobrienget_data (FILE *e, unsigned char *p, unsigned long c, const char *msg)
57838889Sjdp{
57938889Sjdp  unsigned long got;
58038889Sjdp
58138889Sjdp  got = fread (p, 1, c, e);
58238889Sjdp  if (got == c)
58338889Sjdp    return;
58438889Sjdp
58560484Sobrien  fatal (_("%s: read of %lu returned %lu"), msg, c, got);
58638889Sjdp}
58738889Sjdp
58838889Sjdp/* Define an accelerator resource.  */
58938889Sjdp
59038889Sjdpvoid
591130561Sobriendefine_accelerator (struct res_id id, const struct res_res_info *resinfo,
592130561Sobrien		    struct accelerator *data)
59338889Sjdp{
59438889Sjdp  struct res_resource *r;
59538889Sjdp
59660484Sobrien  r = define_standard_resource (&resources, RT_ACCELERATOR, id,
59738889Sjdp				resinfo->language, 0);
59838889Sjdp  r->type = RES_TYPE_ACCELERATOR;
59938889Sjdp  r->u.acc = data;
60038889Sjdp  r->res_info = *resinfo;
60138889Sjdp}
60238889Sjdp
60338889Sjdp/* Define a bitmap resource.  Bitmap data is stored in a file.  The
60438889Sjdp   first 14 bytes of the file are a standard header, which is not
60538889Sjdp   included in the resource data.  */
60638889Sjdp
60738889Sjdp#define BITMAP_SKIP (14)
60838889Sjdp
60938889Sjdpvoid
610130561Sobriendefine_bitmap (struct res_id id, const struct res_res_info *resinfo,
611130561Sobrien	       const char *filename)
61238889Sjdp{
61338889Sjdp  FILE *e;
61438889Sjdp  char *real_filename;
61538889Sjdp  struct stat s;
61638889Sjdp  unsigned char *data;
61738889Sjdp  int i;
61838889Sjdp  struct res_resource *r;
61938889Sjdp
62038889Sjdp  e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
62138889Sjdp
62238889Sjdp  if (stat (real_filename, &s) < 0)
62360484Sobrien    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
62438889Sjdp	   strerror (errno));
62538889Sjdp
62638889Sjdp  data = (unsigned char *) res_alloc (s.st_size - BITMAP_SKIP);
62738889Sjdp
62838889Sjdp  for (i = 0; i < BITMAP_SKIP; i++)
62938889Sjdp    getc (e);
63038889Sjdp
63138889Sjdp  get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
63238889Sjdp
63338889Sjdp  fclose (e);
63438889Sjdp  free (real_filename);
63538889Sjdp
63638889Sjdp  r = define_standard_resource (&resources, RT_BITMAP, id,
63738889Sjdp				resinfo->language, 0);
63838889Sjdp
63938889Sjdp  r->type = RES_TYPE_BITMAP;
64038889Sjdp  r->u.data.length = s.st_size - BITMAP_SKIP;
64138889Sjdp  r->u.data.data = data;
64238889Sjdp  r->res_info = *resinfo;
64338889Sjdp}
64438889Sjdp
64538889Sjdp/* Define a cursor resource.  A cursor file may contain a set of
64638889Sjdp   bitmaps, each representing the same cursor at various different
64738889Sjdp   resolutions.  They each get written out with a different ID.  The
64838889Sjdp   real cursor resource is then a group resource which can be used to
64938889Sjdp   select one of the actual cursors.  */
65038889Sjdp
65138889Sjdpvoid
652130561Sobriendefine_cursor (struct res_id id, const struct res_res_info *resinfo,
653130561Sobrien	       const char *filename)
65438889Sjdp{
65538889Sjdp  FILE *e;
65638889Sjdp  char *real_filename;
65738889Sjdp  int type, count, i;
65838889Sjdp  struct icondir *icondirs;
65938889Sjdp  int first_cursor;
66038889Sjdp  struct res_resource *r;
66138889Sjdp  struct group_cursor *first, **pp;
66238889Sjdp
66338889Sjdp  e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
66438889Sjdp
66538889Sjdp  /* A cursor file is basically an icon file.  The start of the file
66638889Sjdp     is a three word structure.  The first word is ignored.  The
66738889Sjdp     second word is the type of data.  The third word is the number of
66838889Sjdp     entries.  */
66938889Sjdp
67038889Sjdp  get_word (e, real_filename);
67138889Sjdp  type = get_word (e, real_filename);
67238889Sjdp  count = get_word (e, real_filename);
67338889Sjdp  if (type != 2)
67460484Sobrien    fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
67538889Sjdp
67638889Sjdp  /* Read in the icon directory entries.  */
67738889Sjdp
67838889Sjdp  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
67938889Sjdp
68038889Sjdp  for (i = 0; i < count; i++)
68138889Sjdp    {
68238889Sjdp      icondirs[i].width = getc (e);
68338889Sjdp      icondirs[i].height = getc (e);
68438889Sjdp      icondirs[i].colorcount = getc (e);
68538889Sjdp      getc (e);
68638889Sjdp      icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
68738889Sjdp      icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
68838889Sjdp      icondirs[i].bytes = get_long (e, real_filename);
68938889Sjdp      icondirs[i].offset = get_long (e, real_filename);
69038889Sjdp
69138889Sjdp      if (feof (e))
69238889Sjdp	unexpected_eof (real_filename);
69338889Sjdp    }
69438889Sjdp
69538889Sjdp  /* Define each cursor as a unique resource.  */
69638889Sjdp
69738889Sjdp  first_cursor = cursors;
69838889Sjdp
69938889Sjdp  for (i = 0; i < count; i++)
70038889Sjdp    {
70138889Sjdp      unsigned char *data;
70238889Sjdp      struct res_id name;
70338889Sjdp      struct cursor *c;
70438889Sjdp
70538889Sjdp      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
70660484Sobrien	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
70738889Sjdp	       icondirs[i].offset, strerror (errno));
70838889Sjdp
70938889Sjdp      data = (unsigned char *) res_alloc (icondirs[i].bytes);
71038889Sjdp
71138889Sjdp      get_data (e, data, icondirs[i].bytes, real_filename);
71238889Sjdp
71338889Sjdp      c = (struct cursor *) res_alloc (sizeof *c);
71438889Sjdp      c->xhotspot = icondirs[i].u.cursor.xhotspot;
71538889Sjdp      c->yhotspot = icondirs[i].u.cursor.yhotspot;
71638889Sjdp      c->length = icondirs[i].bytes;
71738889Sjdp      c->data = data;
71838889Sjdp
71938889Sjdp      ++cursors;
72038889Sjdp
72138889Sjdp      name.named = 0;
72238889Sjdp      name.u.id = cursors;
72338889Sjdp
72438889Sjdp      r = define_standard_resource (&resources, RT_CURSOR, name,
72538889Sjdp				    resinfo->language, 0);
72638889Sjdp      r->type = RES_TYPE_CURSOR;
72738889Sjdp      r->u.cursor = c;
72838889Sjdp      r->res_info = *resinfo;
72938889Sjdp    }
73038889Sjdp
73138889Sjdp  fclose (e);
73238889Sjdp  free (real_filename);
73338889Sjdp
73438889Sjdp  /* Define a cursor group resource.  */
73538889Sjdp
73638889Sjdp  first = NULL;
73738889Sjdp  pp = &first;
73838889Sjdp  for (i = 0; i < count; i++)
73938889Sjdp    {
74038889Sjdp      struct group_cursor *cg;
74138889Sjdp
74238889Sjdp      cg = (struct group_cursor *) res_alloc (sizeof *cg);
74338889Sjdp      cg->next = NULL;
74438889Sjdp      cg->width = icondirs[i].width;
74538889Sjdp      cg->height = 2 * icondirs[i].height;
74638889Sjdp
74738889Sjdp      /* FIXME: What should these be set to?  */
74838889Sjdp      cg->planes = 1;
74938889Sjdp      cg->bits = 1;
75038889Sjdp
75138889Sjdp      cg->bytes = icondirs[i].bytes + 4;
75238889Sjdp      cg->index = first_cursor + i + 1;
75338889Sjdp
75438889Sjdp      *pp = cg;
75538889Sjdp      pp = &(*pp)->next;
75638889Sjdp    }
75738889Sjdp
75838889Sjdp  free (icondirs);
75938889Sjdp
76038889Sjdp  r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
76138889Sjdp				resinfo->language, 0);
76238889Sjdp  r->type = RES_TYPE_GROUP_CURSOR;
76338889Sjdp  r->u.group_cursor = first;
76438889Sjdp  r->res_info = *resinfo;
76538889Sjdp}
76638889Sjdp
76738889Sjdp/* Define a dialog resource.  */
76838889Sjdp
76938889Sjdpvoid
770130561Sobriendefine_dialog (struct res_id id, const struct res_res_info *resinfo,
771130561Sobrien	       const struct dialog *dialog)
77238889Sjdp{
77338889Sjdp  struct dialog *copy;
77438889Sjdp  struct res_resource *r;
77538889Sjdp
77638889Sjdp  copy = (struct dialog *) res_alloc (sizeof *copy);
77738889Sjdp  *copy = *dialog;
77838889Sjdp
77938889Sjdp  r = define_standard_resource (&resources, RT_DIALOG, id,
78038889Sjdp				resinfo->language, 0);
78138889Sjdp  r->type = RES_TYPE_DIALOG;
78238889Sjdp  r->u.dialog = copy;
78338889Sjdp  r->res_info = *resinfo;
78438889Sjdp}
78538889Sjdp
78638889Sjdp/* Define a dialog control.  This does not define a resource, but
78738889Sjdp   merely allocates and fills in a structure.  */
78838889Sjdp
78938889Sjdpstruct dialog_control *
790130561Sobriendefine_control (const struct res_id iid, unsigned long id, unsigned long x,
791130561Sobrien		unsigned long y, unsigned long width, unsigned long height,
792130561Sobrien		unsigned long class, unsigned long style,
793130561Sobrien		unsigned long exstyle)
79438889Sjdp{
79538889Sjdp  struct dialog_control *n;
79638889Sjdp
79738889Sjdp  n = (struct dialog_control *) res_alloc (sizeof *n);
79838889Sjdp  n->next = NULL;
79938889Sjdp  n->id = id;
80038889Sjdp  n->style = style;
80138889Sjdp  n->exstyle = exstyle;
80238889Sjdp  n->x = x;
80338889Sjdp  n->y = y;
80438889Sjdp  n->width = width;
80538889Sjdp  n->height = height;
80638889Sjdp  n->class.named = 0;
80738889Sjdp  n->class.u.id = class;
808130561Sobrien  n->text = iid;
80938889Sjdp  n->data = NULL;
81038889Sjdp  n->help = 0;
81138889Sjdp
81238889Sjdp  return n;
81338889Sjdp}
81438889Sjdp
81577298Sobrienstruct dialog_control *
816130561Sobriendefine_icon_control (struct res_id iid, unsigned long id, unsigned long x,
817130561Sobrien		     unsigned long y, unsigned long style,
818130561Sobrien		     unsigned long exstyle, unsigned long help,
819130561Sobrien		     struct rcdata_item *data, struct dialog_ex *ex)
82077298Sobrien{
82177298Sobrien  struct dialog_control *n;
822130561Sobrien  struct res_id tid;
823130561Sobrien
82477298Sobrien  if (style == 0)
82577298Sobrien    style = SS_ICON | WS_CHILD | WS_VISIBLE;
826130561Sobrien  res_string_to_id (&tid, "");
827130561Sobrien  n = define_control (tid, id, x, y, 0, 0, CTL_STATIC, style, exstyle);
82877298Sobrien  n->text = iid;
82977298Sobrien  if (help && !ex)
83077298Sobrien    rcparse_warning (_("help ID requires DIALOGEX"));
83177298Sobrien  if (data && !ex)
83277298Sobrien    rcparse_warning (_("control data requires DIALOGEX"));
83377298Sobrien  n->help = help;
83477298Sobrien  n->data = data;
83577298Sobrien
83677298Sobrien  return n;
83777298Sobrien}
83877298Sobrien
83938889Sjdp/* Define a font resource.  */
84038889Sjdp
84138889Sjdpvoid
842130561Sobriendefine_font (struct res_id id, const struct res_res_info *resinfo,
843130561Sobrien	     const char *filename)
84438889Sjdp{
84538889Sjdp  FILE *e;
84638889Sjdp  char *real_filename;
84738889Sjdp  struct stat s;
84838889Sjdp  unsigned char *data;
84938889Sjdp  struct res_resource *r;
85038889Sjdp  long offset;
85138889Sjdp  long fontdatalength;
85238889Sjdp  unsigned char *fontdata;
85338889Sjdp  struct fontdir *fd;
85438889Sjdp  const char *device, *face;
85538889Sjdp  struct fontdir **pp;
85638889Sjdp
85738889Sjdp  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
85838889Sjdp
85938889Sjdp  if (stat (real_filename, &s) < 0)
86060484Sobrien    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
86138889Sjdp	   strerror (errno));
86238889Sjdp
86338889Sjdp  data = (unsigned char *) res_alloc (s.st_size);
86438889Sjdp
86538889Sjdp  get_data (e, data, s.st_size, real_filename);
86638889Sjdp
86738889Sjdp  fclose (e);
86838889Sjdp  free (real_filename);
86938889Sjdp
87038889Sjdp  r = define_standard_resource (&resources, RT_FONT, id,
87138889Sjdp				resinfo->language, 0);
87238889Sjdp
87338889Sjdp  r->type = RES_TYPE_FONT;
87438889Sjdp  r->u.data.length = s.st_size;
87538889Sjdp  r->u.data.data = data;
87638889Sjdp  r->res_info = *resinfo;
87738889Sjdp
87838889Sjdp  /* For each font resource, we must add an entry in the FONTDIR
87938889Sjdp     resource.  The FONTDIR resource includes some strings in the font
88038889Sjdp     file.  To find them, we have to do some magic on the data we have
88138889Sjdp     read.  */
88238889Sjdp
88338889Sjdp  offset = ((((((data[47] << 8)
88438889Sjdp		| data[46]) << 8)
88538889Sjdp	      | data[45]) << 8)
88638889Sjdp	    | data[44]);
88738889Sjdp  if (offset > 0 && offset < s.st_size)
88838889Sjdp    device = (char *) data + offset;
88938889Sjdp  else
89038889Sjdp    device = "";
89138889Sjdp
89238889Sjdp  offset = ((((((data[51] << 8)
89338889Sjdp		| data[50]) << 8)
89438889Sjdp	      | data[49]) << 8)
89538889Sjdp	    | data[48]);
89638889Sjdp  if (offset > 0 && offset < s.st_size)
89738889Sjdp    face = (char *) data + offset;
89838889Sjdp  else
89938889Sjdp    face = "";
90038889Sjdp
90138889Sjdp  ++fonts;
90238889Sjdp
90338889Sjdp  fontdatalength = 58 + strlen (device) + strlen (face);
90438889Sjdp  fontdata = (unsigned char *) res_alloc (fontdatalength);
90538889Sjdp  memcpy (fontdata, data, 56);
90638889Sjdp  strcpy ((char *) fontdata + 56, device);
90738889Sjdp  strcpy ((char *) fontdata + 57 + strlen (device), face);
90838889Sjdp
90938889Sjdp  fd = (struct fontdir *) res_alloc (sizeof *fd);
91038889Sjdp  fd->next = NULL;
91138889Sjdp  fd->index = fonts;
91238889Sjdp  fd->length = fontdatalength;
91338889Sjdp  fd->data = fontdata;
91438889Sjdp
91538889Sjdp  for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
91638889Sjdp    ;
91738889Sjdp  *pp = fd;
91838889Sjdp
91938889Sjdp  /* For the single fontdirs resource, we always use the resource
92038889Sjdp     information of the last font.  I don't know what else to do.  */
92138889Sjdp  fontdirs_resinfo = *resinfo;
92238889Sjdp}
92338889Sjdp
92438889Sjdp/* Define the fontdirs resource.  This is called after the entire rc
92538889Sjdp   file has been parsed, if any font resources were seen.  */
92638889Sjdp
92738889Sjdpstatic void
928130561Sobriendefine_fontdirs (void)
92938889Sjdp{
93038889Sjdp  struct res_resource *r;
93138889Sjdp  struct res_id id;
93238889Sjdp
93338889Sjdp  id.named = 0;
93438889Sjdp  id.u.id = 1;
93538889Sjdp
93638889Sjdp  r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
93738889Sjdp
93838889Sjdp  r->type = RES_TYPE_FONTDIR;
93938889Sjdp  r->u.fontdir = fontdirs;
94038889Sjdp  r->res_info = fontdirs_resinfo;
94138889Sjdp}
94238889Sjdp
94338889Sjdp/* Define an icon resource.  An icon file may contain a set of
94438889Sjdp   bitmaps, each representing the same icon at various different
94538889Sjdp   resolutions.  They each get written out with a different ID.  The
94638889Sjdp   real icon resource is then a group resource which can be used to
94738889Sjdp   select one of the actual icon bitmaps.  */
94838889Sjdp
94938889Sjdpvoid
950130561Sobriendefine_icon (struct res_id id, const struct res_res_info *resinfo,
951130561Sobrien	     const char *filename)
95238889Sjdp{
95338889Sjdp  FILE *e;
95438889Sjdp  char *real_filename;
95538889Sjdp  int type, count, i;
95638889Sjdp  struct icondir *icondirs;
95738889Sjdp  int first_icon;
95838889Sjdp  struct res_resource *r;
95938889Sjdp  struct group_icon *first, **pp;
96038889Sjdp
96138889Sjdp  e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
96238889Sjdp
96338889Sjdp  /* The start of an icon file is a three word structure.  The first
96438889Sjdp     word is ignored.  The second word is the type of data.  The third
96538889Sjdp     word is the number of entries.  */
96638889Sjdp
96738889Sjdp  get_word (e, real_filename);
96838889Sjdp  type = get_word (e, real_filename);
96938889Sjdp  count = get_word (e, real_filename);
97038889Sjdp  if (type != 1)
97160484Sobrien    fatal (_("icon file `%s' does not contain icon data"), real_filename);
97238889Sjdp
97338889Sjdp  /* Read in the icon directory entries.  */
97438889Sjdp
97538889Sjdp  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
97638889Sjdp
97738889Sjdp  for (i = 0; i < count; i++)
97838889Sjdp    {
97938889Sjdp      icondirs[i].width = getc (e);
98038889Sjdp      icondirs[i].height = getc (e);
98138889Sjdp      icondirs[i].colorcount = getc (e);
98238889Sjdp      getc (e);
98338889Sjdp      icondirs[i].u.icon.planes = get_word (e, real_filename);
98438889Sjdp      icondirs[i].u.icon.bits = get_word (e, real_filename);
98538889Sjdp      icondirs[i].bytes = get_long (e, real_filename);
98638889Sjdp      icondirs[i].offset = get_long (e, real_filename);
98738889Sjdp
98838889Sjdp      if (feof (e))
98938889Sjdp	unexpected_eof (real_filename);
99038889Sjdp    }
99138889Sjdp
99238889Sjdp  /* Define each icon as a unique resource.  */
99338889Sjdp
99438889Sjdp  first_icon = icons;
99538889Sjdp
99638889Sjdp  for (i = 0; i < count; i++)
99738889Sjdp    {
99838889Sjdp      unsigned char *data;
99938889Sjdp      struct res_id name;
100038889Sjdp
100138889Sjdp      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
100260484Sobrien	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
100338889Sjdp	       icondirs[i].offset, strerror (errno));
100438889Sjdp
100538889Sjdp      data = (unsigned char *) res_alloc (icondirs[i].bytes);
100638889Sjdp
100738889Sjdp      get_data (e, data, icondirs[i].bytes, real_filename);
100838889Sjdp
100938889Sjdp      ++icons;
101038889Sjdp
101138889Sjdp      name.named = 0;
101238889Sjdp      name.u.id = icons;
101338889Sjdp
101438889Sjdp      r = define_standard_resource (&resources, RT_ICON, name,
101538889Sjdp				    resinfo->language, 0);
101638889Sjdp      r->type = RES_TYPE_ICON;
101738889Sjdp      r->u.data.length = icondirs[i].bytes;
101838889Sjdp      r->u.data.data = data;
101938889Sjdp      r->res_info = *resinfo;
102038889Sjdp    }
102138889Sjdp
102238889Sjdp  fclose (e);
102338889Sjdp  free (real_filename);
102438889Sjdp
102538889Sjdp  /* Define an icon group resource.  */
102638889Sjdp
102738889Sjdp  first = NULL;
102838889Sjdp  pp = &first;
102938889Sjdp  for (i = 0; i < count; i++)
103038889Sjdp    {
103138889Sjdp      struct group_icon *cg;
103238889Sjdp
103338889Sjdp      /* For some reason, at least in some files the planes and bits
103438889Sjdp         are zero.  We instead set them from the color.  This is
103538889Sjdp         copied from rcl.  */
103638889Sjdp
103738889Sjdp      cg = (struct group_icon *) res_alloc (sizeof *cg);
103838889Sjdp      cg->next = NULL;
103938889Sjdp      cg->width = icondirs[i].width;
104038889Sjdp      cg->height = icondirs[i].height;
104138889Sjdp      cg->colors = icondirs[i].colorcount;
104238889Sjdp
1043130561Sobrien      if (icondirs[i].u.icon.planes)
1044130561Sobrien	cg->planes = icondirs[i].u.icon.planes;
1045130561Sobrien      else
1046130561Sobrien	cg->planes = 1;
104738889Sjdp
1048130561Sobrien      if (icondirs[i].u.icon.bits)
1049130561Sobrien	cg->bits = icondirs[i].u.icon.bits;
1050130561Sobrien      else
1051130561Sobrien	{
1052130561Sobrien	  cg->bits = 0;
1053130561Sobrien
1054130561Sobrien	  while ((1L << cg->bits) < cg->colors)
1055130561Sobrien	    ++cg->bits;
1056130561Sobrien	}
1057130561Sobrien
105838889Sjdp      cg->bytes = icondirs[i].bytes;
105938889Sjdp      cg->index = first_icon + i + 1;
106038889Sjdp
106138889Sjdp      *pp = cg;
106238889Sjdp      pp = &(*pp)->next;
106338889Sjdp    }
106438889Sjdp
106538889Sjdp  free (icondirs);
106638889Sjdp
106738889Sjdp  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
106838889Sjdp				resinfo->language, 0);
106938889Sjdp  r->type = RES_TYPE_GROUP_ICON;
107038889Sjdp  r->u.group_icon = first;
107138889Sjdp  r->res_info = *resinfo;
107238889Sjdp}
107338889Sjdp
107438889Sjdp/* Define a menu resource.  */
107538889Sjdp
107638889Sjdpvoid
1077130561Sobriendefine_menu (struct res_id id, const struct res_res_info *resinfo,
1078130561Sobrien	     struct menuitem *menuitems)
107938889Sjdp{
108038889Sjdp  struct menu *m;
108138889Sjdp  struct res_resource *r;
108238889Sjdp
108338889Sjdp  m = (struct menu *) res_alloc (sizeof *m);
108438889Sjdp  m->items = menuitems;
108538889Sjdp  m->help = 0;
108638889Sjdp
108738889Sjdp  r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
108838889Sjdp  r->type = RES_TYPE_MENU;
108938889Sjdp  r->u.menu = m;
109038889Sjdp  r->res_info = *resinfo;
109138889Sjdp}
109238889Sjdp
109338889Sjdp/* Define a menu item.  This does not define a resource, but merely
109438889Sjdp   allocates and fills in a structure.  */
109538889Sjdp
109638889Sjdpstruct menuitem *
1097130561Sobriendefine_menuitem (const char *text, int menuid, unsigned long type,
1098130561Sobrien		 unsigned long state, unsigned long help,
1099130561Sobrien		 struct menuitem *menuitems)
110038889Sjdp{
110138889Sjdp  struct menuitem *mi;
110238889Sjdp
110338889Sjdp  mi = (struct menuitem *) res_alloc (sizeof *mi);
110438889Sjdp  mi->next = NULL;
110538889Sjdp  mi->type = type;
110638889Sjdp  mi->state = state;
110738889Sjdp  mi->id = menuid;
110838889Sjdp  if (text == NULL)
110938889Sjdp    mi->text = NULL;
111038889Sjdp  else
111138889Sjdp    unicode_from_ascii ((int *) NULL, &mi->text, text);
111238889Sjdp  mi->help = help;
111338889Sjdp  mi->popup = menuitems;
111438889Sjdp  return mi;
111538889Sjdp}
111638889Sjdp
111738889Sjdp/* Define a messagetable resource.  */
111838889Sjdp
111938889Sjdpvoid
1120130561Sobriendefine_messagetable (struct res_id id, const struct res_res_info *resinfo,
1121130561Sobrien		     const char *filename)
112238889Sjdp{
112338889Sjdp  FILE *e;
112438889Sjdp  char *real_filename;
112538889Sjdp  struct stat s;
112638889Sjdp  unsigned char *data;
112738889Sjdp  struct res_resource *r;
112838889Sjdp
112938889Sjdp  e = open_file_search (filename, FOPEN_RB, "messagetable file",
113038889Sjdp			&real_filename);
113138889Sjdp
113238889Sjdp  if (stat (real_filename, &s) < 0)
113360484Sobrien    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
113438889Sjdp	   strerror (errno));
113538889Sjdp
113638889Sjdp  data = (unsigned char *) res_alloc (s.st_size);
113738889Sjdp
113838889Sjdp  get_data (e, data, s.st_size, real_filename);
113938889Sjdp
114038889Sjdp  fclose (e);
114138889Sjdp  free (real_filename);
114238889Sjdp
114338889Sjdp  r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
114438889Sjdp				resinfo->language, 0);
114538889Sjdp
114638889Sjdp  r->type = RES_TYPE_MESSAGETABLE;
114738889Sjdp  r->u.data.length = s.st_size;
114838889Sjdp  r->u.data.data = data;
114938889Sjdp  r->res_info = *resinfo;
115038889Sjdp}
115138889Sjdp
115238889Sjdp/* Define an rcdata resource.  */
115338889Sjdp
115438889Sjdpvoid
1155130561Sobriendefine_rcdata (struct res_id id, const struct res_res_info *resinfo,
1156130561Sobrien	       struct rcdata_item *data)
115738889Sjdp{
115838889Sjdp  struct res_resource *r;
115938889Sjdp
116038889Sjdp  r = define_standard_resource (&resources, RT_RCDATA, id,
116138889Sjdp				resinfo->language, 0);
116238889Sjdp  r->type = RES_TYPE_RCDATA;
116338889Sjdp  r->u.rcdata = data;
116438889Sjdp  r->res_info = *resinfo;
116538889Sjdp}
116638889Sjdp
116738889Sjdp/* Create an rcdata item holding a string.  */
116838889Sjdp
116938889Sjdpstruct rcdata_item *
1170130561Sobriendefine_rcdata_string (const char *string, unsigned long len)
117138889Sjdp{
117238889Sjdp  struct rcdata_item *ri;
117338889Sjdp  char *s;
117438889Sjdp
117538889Sjdp  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
117638889Sjdp  ri->next = NULL;
117738889Sjdp  ri->type = RCDATA_STRING;
117838889Sjdp  ri->u.string.length = len;
117938889Sjdp  s = (char *) res_alloc (len);
118038889Sjdp  memcpy (s, string, len);
118138889Sjdp  ri->u.string.s = s;
118238889Sjdp
118338889Sjdp  return ri;
118438889Sjdp}
118538889Sjdp
118638889Sjdp/* Create an rcdata item holding a number.  */
118738889Sjdp
118838889Sjdpstruct rcdata_item *
1189130561Sobriendefine_rcdata_number (unsigned long val, int dword)
119038889Sjdp{
119138889Sjdp  struct rcdata_item *ri;
119238889Sjdp
119338889Sjdp  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
119438889Sjdp  ri->next = NULL;
119538889Sjdp  ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
119638889Sjdp  ri->u.word = val;
119738889Sjdp
119838889Sjdp  return ri;
119938889Sjdp}
120038889Sjdp
120138889Sjdp/* Define a stringtable resource.  This is called for each string
120238889Sjdp   which appears in a STRINGTABLE statement.  */
120338889Sjdp
120438889Sjdpvoid
1205130561Sobriendefine_stringtable (const struct res_res_info *resinfo,
1206130561Sobrien		    unsigned long stringid, const char *string)
120738889Sjdp{
120838889Sjdp  struct res_id id;
120938889Sjdp  struct res_resource *r;
121038889Sjdp
121138889Sjdp  id.named = 0;
121238889Sjdp  id.u.id = (stringid >> 4) + 1;
121338889Sjdp  r = define_standard_resource (&resources, RT_STRING, id,
121438889Sjdp				resinfo->language, 1);
121538889Sjdp
121638889Sjdp  if (r->type == RES_TYPE_UNINITIALIZED)
121738889Sjdp    {
121838889Sjdp      int i;
121938889Sjdp
122038889Sjdp      r->type = RES_TYPE_STRINGTABLE;
122138889Sjdp      r->u.stringtable = ((struct stringtable *)
122238889Sjdp			  res_alloc (sizeof (struct stringtable)));
122338889Sjdp      for (i = 0; i < 16; i++)
122438889Sjdp	{
122538889Sjdp	  r->u.stringtable->strings[i].length = 0;
122638889Sjdp	  r->u.stringtable->strings[i].string = NULL;
122738889Sjdp	}
122838889Sjdp
122938889Sjdp      r->res_info = *resinfo;
123038889Sjdp    }
123138889Sjdp
123238889Sjdp  unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
123338889Sjdp		      &r->u.stringtable->strings[stringid & 0xf].string,
123438889Sjdp		      string);
123538889Sjdp}
123638889Sjdp
123738889Sjdp/* Define a user data resource where the data is in the rc file.  */
123838889Sjdp
123938889Sjdpvoid
1240130561Sobriendefine_user_data (struct res_id id, struct res_id type,
1241130561Sobrien		  const struct res_res_info *resinfo,
1242130561Sobrien		  struct rcdata_item *data)
124338889Sjdp{
124438889Sjdp  struct res_id ids[3];
124538889Sjdp  struct res_resource *r;
124638889Sjdp
124738889Sjdp  ids[0] = type;
124838889Sjdp  ids[1] = id;
124938889Sjdp  ids[2].named = 0;
125038889Sjdp  ids[2].u.id = resinfo->language;
125138889Sjdp
125238889Sjdp  r = define_resource (&resources, 3, ids, 0);
125338889Sjdp  r->type = RES_TYPE_USERDATA;
125438889Sjdp  r->u.userdata = data;
125538889Sjdp  r->res_info = *resinfo;
125638889Sjdp}
125738889Sjdp
125838889Sjdp/* Define a user data resource where the data is in a file.  */
125938889Sjdp
126038889Sjdpvoid
1261130561Sobriendefine_user_file (struct res_id id, struct res_id type,
1262130561Sobrien		  const struct res_res_info *resinfo, const char *filename)
126338889Sjdp{
126438889Sjdp  FILE *e;
126538889Sjdp  char *real_filename;
126638889Sjdp  struct stat s;
126738889Sjdp  unsigned char *data;
126838889Sjdp  struct res_id ids[3];
126938889Sjdp  struct res_resource *r;
127038889Sjdp
127138889Sjdp  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
127238889Sjdp
127338889Sjdp  if (stat (real_filename, &s) < 0)
127460484Sobrien    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
127538889Sjdp	   strerror (errno));
127638889Sjdp
127738889Sjdp  data = (unsigned char *) res_alloc (s.st_size);
127838889Sjdp
127938889Sjdp  get_data (e, data, s.st_size, real_filename);
128038889Sjdp
128138889Sjdp  fclose (e);
128238889Sjdp  free (real_filename);
128338889Sjdp
128438889Sjdp  ids[0] = type;
128538889Sjdp  ids[1] = id;
128638889Sjdp  ids[2].named = 0;
128738889Sjdp  ids[2].u.id = resinfo->language;
128838889Sjdp
128938889Sjdp  r = define_resource (&resources, 3, ids, 0);
129038889Sjdp  r->type = RES_TYPE_USERDATA;
129138889Sjdp  r->u.userdata = ((struct rcdata_item *)
129238889Sjdp		   res_alloc (sizeof (struct rcdata_item)));
129338889Sjdp  r->u.userdata->next = NULL;
129438889Sjdp  r->u.userdata->type = RCDATA_BUFFER;
129538889Sjdp  r->u.userdata->u.buffer.length = s.st_size;
129638889Sjdp  r->u.userdata->u.buffer.data = data;
129738889Sjdp  r->res_info = *resinfo;
129838889Sjdp}
129938889Sjdp
130038889Sjdp/* Define a versioninfo resource.  */
130138889Sjdp
130238889Sjdpvoid
1303130561Sobriendefine_versioninfo (struct res_id id, int language,
1304130561Sobrien		    struct fixed_versioninfo *fixedverinfo,
1305130561Sobrien		    struct ver_info *verinfo)
130638889Sjdp{
130738889Sjdp  struct res_resource *r;
130838889Sjdp
130938889Sjdp  r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
131038889Sjdp  r->type = RES_TYPE_VERSIONINFO;
131138889Sjdp  r->u.versioninfo = ((struct versioninfo *)
131238889Sjdp		      res_alloc (sizeof (struct versioninfo)));
131338889Sjdp  r->u.versioninfo->fixed = fixedverinfo;
131438889Sjdp  r->u.versioninfo->var = verinfo;
131538889Sjdp  r->res_info.language = language;
131638889Sjdp}
131738889Sjdp
131838889Sjdp/* Add string version info to a list of version information.  */
131938889Sjdp
132038889Sjdpstruct ver_info *
1321130561Sobrienappend_ver_stringfileinfo (struct ver_info *verinfo, const char *language,
1322130561Sobrien			   struct ver_stringinfo *strings)
132338889Sjdp{
132438889Sjdp  struct ver_info *vi, **pp;
132538889Sjdp
132638889Sjdp  vi = (struct ver_info *) res_alloc (sizeof *vi);
132738889Sjdp  vi->next = NULL;
132838889Sjdp  vi->type = VERINFO_STRING;
132938889Sjdp  unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
133038889Sjdp  vi->u.string.strings = strings;
133138889Sjdp
133238889Sjdp  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
133338889Sjdp    ;
133438889Sjdp  *pp = vi;
133538889Sjdp
133638889Sjdp  return verinfo;
133738889Sjdp}
133838889Sjdp
133938889Sjdp/* Add variable version info to a list of version information.  */
134038889Sjdp
134138889Sjdpstruct ver_info *
1342130561Sobrienappend_ver_varfileinfo (struct ver_info *verinfo, const char *key,
1343130561Sobrien			struct ver_varinfo *var)
134438889Sjdp{
134538889Sjdp  struct ver_info *vi, **pp;
134638889Sjdp
134738889Sjdp  vi = (struct ver_info *) res_alloc (sizeof *vi);
134838889Sjdp  vi->next = NULL;
134938889Sjdp  vi->type = VERINFO_VAR;
135038889Sjdp  unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
135138889Sjdp  vi->u.var.var = var;
135238889Sjdp
135338889Sjdp  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
135438889Sjdp    ;
135538889Sjdp  *pp = vi;
135638889Sjdp
135738889Sjdp  return verinfo;
135838889Sjdp}
135938889Sjdp
136038889Sjdp/* Append version string information to a list.  */
136138889Sjdp
136238889Sjdpstruct ver_stringinfo *
1363130561Sobrienappend_verval (struct ver_stringinfo *strings, const char *key,
1364130561Sobrien	       const char *value)
136538889Sjdp{
136638889Sjdp  struct ver_stringinfo *vs, **pp;
136738889Sjdp
136838889Sjdp  vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
136938889Sjdp  vs->next = NULL;
137038889Sjdp  unicode_from_ascii ((int *) NULL, &vs->key, key);
137138889Sjdp  unicode_from_ascii ((int *) NULL, &vs->value, value);
137238889Sjdp
137338889Sjdp  for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
137438889Sjdp    ;
137538889Sjdp  *pp = vs;
137638889Sjdp
137738889Sjdp  return strings;
137838889Sjdp}
137938889Sjdp
138038889Sjdp/* Append version variable information to a list.  */
138138889Sjdp
138238889Sjdpstruct ver_varinfo *
1383130561Sobrienappend_vertrans (struct ver_varinfo *var, unsigned long language,
1384130561Sobrien		 unsigned long charset)
138538889Sjdp{
138638889Sjdp  struct ver_varinfo *vv, **pp;
138738889Sjdp
138838889Sjdp  vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
138938889Sjdp  vv->next = NULL;
139038889Sjdp  vv->language = language;
139138889Sjdp  vv->charset = charset;
139238889Sjdp
139338889Sjdp  for (pp = &var; *pp != NULL; pp = &(*pp)->next)
139438889Sjdp    ;
139538889Sjdp  *pp = vv;
139638889Sjdp
139738889Sjdp  return var;
139838889Sjdp}
139938889Sjdp
140038889Sjdp/* Local functions used to write out an rc file.  */
140138889Sjdp
1402130561Sobrienstatic void indent (FILE *, int);
140338889Sjdpstatic void write_rc_directory
1404130561Sobrien  (FILE *, const struct res_directory *, const struct res_id *,
1405130561Sobrien   const struct res_id *, int *, int);
140638889Sjdpstatic void write_rc_subdir
1407130561Sobrien  (FILE *, const struct res_entry *, const struct res_id *,
1408130561Sobrien   const struct res_id *, int *, int);
140938889Sjdpstatic void write_rc_resource
1410130561Sobrien  (FILE *, const struct res_id *, const struct res_id *,
1411130561Sobrien   const struct res_resource *, int *);
1412130561Sobrienstatic void write_rc_accelerators (FILE *, const struct accelerator *);
1413130561Sobrienstatic void write_rc_cursor (FILE *, const struct cursor *);
1414130561Sobrienstatic void write_rc_group_cursor (FILE *, const struct group_cursor *);
1415130561Sobrienstatic void write_rc_dialog (FILE *, const struct dialog *);
1416130561Sobrienstatic void write_rc_dialog_control (FILE *, const struct dialog_control *);
1417130561Sobrienstatic void write_rc_fontdir (FILE *, const struct fontdir *);
1418130561Sobrienstatic void write_rc_group_icon (FILE *, const struct group_icon *);
1419130561Sobrienstatic void write_rc_menu (FILE *, const struct menu *, int);
1420130561Sobrienstatic void write_rc_menuitems (FILE *, const struct menuitem *, int, int);
1421130561Sobrienstatic void write_rc_rcdata (FILE *, const struct rcdata_item *, int);
142238889Sjdpstatic void write_rc_stringtable
1423130561Sobrien  (FILE *, const struct res_id *, const struct stringtable *);
1424130561Sobrienstatic void write_rc_versioninfo (FILE *, const struct versioninfo *);
1425130561Sobrienstatic void write_rc_filedata (FILE *, unsigned long, const unsigned char *);
142638889Sjdp
142738889Sjdp/* Indent a given number of spaces.  */
142838889Sjdp
142938889Sjdpstatic void
1430130561Sobrienindent (FILE *e, int c)
143138889Sjdp{
143238889Sjdp  int i;
143338889Sjdp
143438889Sjdp  for (i = 0; i < c; i++)
143538889Sjdp    putc (' ', e);
143638889Sjdp}
143738889Sjdp
143838889Sjdp/* Dump the resources we have read in the format of an rc file.
143938889Sjdp
144038889Sjdp   Actually, we don't use the format of an rc file, because it's way
144138889Sjdp   too much of a pain--for example, we'd have to write icon resources
144238889Sjdp   into a file and refer to that file.  We just generate a readable
144338889Sjdp   format that kind of looks like an rc file, and is useful for
144438889Sjdp   understanding the contents of a resource file.  Someday we may want
144538889Sjdp   to generate an rc file which the rc compiler can read; if that day
144638889Sjdp   comes, this code will have to be fixed up.  */
144738889Sjdp
144838889Sjdpvoid
1449130561Sobrienwrite_rc_file (const char *filename, const struct res_directory *resources)
145038889Sjdp{
145138889Sjdp  FILE *e;
145238889Sjdp  int language;
145338889Sjdp
145438889Sjdp  if (filename == NULL)
145538889Sjdp    e = stdout;
145638889Sjdp  else
145738889Sjdp    {
145838889Sjdp      e = fopen (filename, FOPEN_WT);
145938889Sjdp      if (e == NULL)
146060484Sobrien	fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
146138889Sjdp    }
146238889Sjdp
146338889Sjdp  language = -1;
146438889Sjdp  write_rc_directory (e, resources, (const struct res_id *) NULL,
146538889Sjdp		      (const struct res_id *) NULL, &language, 1);
146638889Sjdp}
146738889Sjdp
146838889Sjdp/* Write out a directory.  E is the file to write to.  RD is the
146938889Sjdp   directory.  TYPE is a pointer to the level 1 ID which serves as the
147038889Sjdp   resource type.  NAME is a pointer to the level 2 ID which serves as
147138889Sjdp   an individual resource name.  LANGUAGE is a pointer to the current
147238889Sjdp   language.  LEVEL is the level in the tree.  */
147338889Sjdp
147438889Sjdpstatic void
1475130561Sobrienwrite_rc_directory (FILE *e, const struct res_directory *rd,
1476130561Sobrien		    const struct res_id *type, const struct res_id *name,
1477130561Sobrien		    int *language, int level)
147838889Sjdp{
147938889Sjdp  const struct res_entry *re;
148038889Sjdp
148138889Sjdp  /* Print out some COFF information that rc files can't represent.  */
148238889Sjdp
148338889Sjdp  if (rd->time != 0)
148438889Sjdp    fprintf (e, "// Time stamp: %lu\n", rd->time);
148538889Sjdp  if (rd->characteristics != 0)
148638889Sjdp    fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
148738889Sjdp  if (rd->major != 0 || rd->minor != 0)
148838889Sjdp    fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
148938889Sjdp
149038889Sjdp  for (re = rd->entries;  re != NULL; re = re->next)
149138889Sjdp    {
149238889Sjdp      switch (level)
149338889Sjdp	{
149438889Sjdp	case 1:
149538889Sjdp	  /* If we're at level 1, the key of this resource is the
149638889Sjdp             type.  This normally duplicates the information we have
149738889Sjdp             stored with the resource itself, but we need to remember
149838889Sjdp             the type if this is a user define resource type.  */
149938889Sjdp	  type = &re->id;
150038889Sjdp	  break;
150138889Sjdp
150238889Sjdp	case 2:
150338889Sjdp	  /* If we're at level 2, the key of this resource is the name
150499461Sobrien	     we are going to use in the rc printout.  */
150538889Sjdp	  name = &re->id;
150638889Sjdp	  break;
150738889Sjdp
150838889Sjdp	case 3:
150938889Sjdp	  /* If we're at level 3, then this key represents a language.
151038889Sjdp	     Use it to update the current language.  */
151138889Sjdp	  if (! re->id.named
151260484Sobrien	      && re->id.u.id != (unsigned long) (unsigned int) *language
151338889Sjdp	      && (re->id.u.id & 0xffff) == re->id.u.id)
151438889Sjdp	    {
151538889Sjdp	      fprintf (e, "LANGUAGE %lu, %lu\n",
1516104834Sobrien		       re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
151799461Sobrien		       (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
151838889Sjdp	      *language = re->id.u.id;
151938889Sjdp	    }
152038889Sjdp	  break;
152138889Sjdp
152238889Sjdp	default:
152338889Sjdp	  break;
152438889Sjdp	}
152538889Sjdp
152638889Sjdp      if (re->subdir)
152738889Sjdp	write_rc_subdir (e, re, type, name, language, level);
152838889Sjdp      else
152938889Sjdp	{
153038889Sjdp	  if (level == 3)
153138889Sjdp	    {
153238889Sjdp	      /* This is the normal case: the three levels are
153338889Sjdp                 TYPE/NAME/LANGUAGE.  NAME will have been set at level
153438889Sjdp                 2, and represents the name to use.  We probably just
153538889Sjdp                 set LANGUAGE, and it will probably match what the
153638889Sjdp                 resource itself records if anything.  */
153738889Sjdp	      write_rc_resource (e, type, name, re->u.res, language);
153838889Sjdp	    }
153938889Sjdp	  else
154038889Sjdp	    {
154138889Sjdp	      fprintf (e, "// Resource at unexpected level %d\n", level);
154238889Sjdp	      write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
154338889Sjdp				 language);
154438889Sjdp	    }
154538889Sjdp	}
154638889Sjdp    }
154738889Sjdp}
154838889Sjdp
154938889Sjdp/* Write out a subdirectory entry.  E is the file to write to.  RE is
155038889Sjdp   the subdirectory entry.  TYPE and NAME are pointers to higher level
155138889Sjdp   IDs, or NULL.  LANGUAGE is a pointer to the current language.
155238889Sjdp   LEVEL is the level in the tree.  */
155338889Sjdp
155438889Sjdpstatic void
1555130561Sobrienwrite_rc_subdir (FILE *e, const struct res_entry *re,
1556130561Sobrien		 const struct res_id *type, const struct res_id *name,
1557130561Sobrien		 int *language, int level)
155838889Sjdp{
155938889Sjdp  fprintf (e, "\n");
156038889Sjdp  switch (level)
156138889Sjdp    {
156238889Sjdp    case 1:
156338889Sjdp      fprintf (e, "// Type: ");
156438889Sjdp      if (re->id.named)
156538889Sjdp	res_id_print (e, re->id, 1);
156638889Sjdp      else
156738889Sjdp	{
156838889Sjdp	  const char *s;
156938889Sjdp
157038889Sjdp	  switch (re->id.u.id)
157138889Sjdp	    {
157238889Sjdp	    case RT_CURSOR: s = "cursor"; break;
157338889Sjdp	    case RT_BITMAP: s = "bitmap"; break;
157438889Sjdp	    case RT_ICON: s = "icon"; break;
157538889Sjdp	    case RT_MENU: s = "menu"; break;
157638889Sjdp	    case RT_DIALOG: s = "dialog"; break;
157738889Sjdp	    case RT_STRING: s = "stringtable"; break;
157838889Sjdp	    case RT_FONTDIR: s = "fontdir"; break;
157938889Sjdp	    case RT_FONT: s = "font"; break;
158060484Sobrien	    case RT_ACCELERATOR: s = "accelerators"; break;
158138889Sjdp	    case RT_RCDATA: s = "rcdata"; break;
158238889Sjdp	    case RT_MESSAGETABLE: s = "messagetable"; break;
158338889Sjdp	    case RT_GROUP_CURSOR: s = "group cursor"; break;
158438889Sjdp	    case RT_GROUP_ICON: s = "group icon"; break;
158538889Sjdp	    case RT_VERSION: s = "version"; break;
158638889Sjdp	    case RT_DLGINCLUDE: s = "dlginclude"; break;
158738889Sjdp	    case RT_PLUGPLAY: s = "plugplay"; break;
158838889Sjdp	    case RT_VXD: s = "vxd"; break;
158938889Sjdp	    case RT_ANICURSOR: s = "anicursor"; break;
159038889Sjdp	    case RT_ANIICON: s = "aniicon"; break;
159138889Sjdp	    default: s = NULL; break;
159238889Sjdp	    }
159338889Sjdp
159438889Sjdp	  if (s != NULL)
159538889Sjdp	    fprintf (e, "%s", s);
159638889Sjdp	  else
159738889Sjdp	    res_id_print (e, re->id, 1);
159838889Sjdp	}
159938889Sjdp      fprintf (e, "\n");
160038889Sjdp      break;
160138889Sjdp
160238889Sjdp    case 2:
160338889Sjdp      fprintf (e, "// Name: ");
160438889Sjdp      res_id_print (e, re->id, 1);
160538889Sjdp      fprintf (e, "\n");
160638889Sjdp      break;
160738889Sjdp
160838889Sjdp    case 3:
160938889Sjdp      fprintf (e, "// Language: ");
161038889Sjdp      res_id_print (e, re->id, 1);
161138889Sjdp      fprintf (e, "\n");
161238889Sjdp      break;
161338889Sjdp
161438889Sjdp    default:
161538889Sjdp      fprintf (e, "// Level %d: ", level);
161638889Sjdp      res_id_print (e, re->id, 1);
161738889Sjdp      fprintf (e, "\n");
1618104834Sobrien    }
161938889Sjdp
162038889Sjdp  write_rc_directory (e, re->u.dir, type, name, language, level + 1);
162138889Sjdp}
162238889Sjdp
162338889Sjdp/* Write out a single resource.  E is the file to write to.  TYPE is a
162438889Sjdp   pointer to the type of the resource.  NAME is a pointer to the name
162538889Sjdp   of the resource; it will be NULL if there is a level mismatch.  RES
162638889Sjdp   is the resource data.  LANGUAGE is a pointer to the current
162738889Sjdp   language.  */
162838889Sjdp
162938889Sjdpstatic void
1630130561Sobrienwrite_rc_resource (FILE *e, const struct res_id *type,
1631130561Sobrien		   const struct res_id *name, const struct res_resource *res,
1632130561Sobrien		   int *language)
163338889Sjdp{
163438889Sjdp  const char *s;
163538889Sjdp  int rt;
163638889Sjdp  int menuex = 0;
163738889Sjdp
163838889Sjdp  fprintf (e, "\n");
163938889Sjdp
164038889Sjdp  switch (res->type)
164138889Sjdp    {
164238889Sjdp    default:
164338889Sjdp      abort ();
164438889Sjdp
164538889Sjdp    case RES_TYPE_ACCELERATOR:
164638889Sjdp      s = "ACCELERATOR";
164760484Sobrien      rt = RT_ACCELERATOR;
164838889Sjdp      break;
164938889Sjdp
165038889Sjdp    case RES_TYPE_BITMAP:
165138889Sjdp      s = "BITMAP";
165238889Sjdp      rt = RT_BITMAP;
165338889Sjdp      break;
165438889Sjdp
165538889Sjdp    case RES_TYPE_CURSOR:
165638889Sjdp      s = "CURSOR";
165738889Sjdp      rt = RT_CURSOR;
165838889Sjdp      break;
165938889Sjdp
166038889Sjdp    case RES_TYPE_GROUP_CURSOR:
166138889Sjdp      s = "GROUP_CURSOR";
166238889Sjdp      rt = RT_GROUP_CURSOR;
166338889Sjdp      break;
166438889Sjdp
166538889Sjdp    case RES_TYPE_DIALOG:
166638889Sjdp      if (extended_dialog (res->u.dialog))
166738889Sjdp	s = "DIALOGEX";
166838889Sjdp      else
166938889Sjdp	s = "DIALOG";
167038889Sjdp      rt = RT_DIALOG;
167138889Sjdp      break;
167238889Sjdp
167338889Sjdp    case RES_TYPE_FONT:
167438889Sjdp      s = "FONT";
167538889Sjdp      rt = RT_FONT;
167638889Sjdp      break;
167738889Sjdp
167838889Sjdp    case RES_TYPE_FONTDIR:
167938889Sjdp      s = "FONTDIR";
168038889Sjdp      rt = RT_FONTDIR;
168138889Sjdp      break;
168238889Sjdp
168338889Sjdp    case RES_TYPE_ICON:
168438889Sjdp      s = "ICON";
168538889Sjdp      rt = RT_ICON;
168638889Sjdp      break;
168738889Sjdp
168838889Sjdp    case RES_TYPE_GROUP_ICON:
168938889Sjdp      s = "GROUP_ICON";
169038889Sjdp      rt = RT_GROUP_ICON;
169138889Sjdp      break;
169238889Sjdp
169338889Sjdp    case RES_TYPE_MENU:
169438889Sjdp      if (extended_menu (res->u.menu))
169538889Sjdp	{
169638889Sjdp	  s = "MENUEX";
169738889Sjdp	  menuex = 1;
169838889Sjdp	}
169938889Sjdp      else
170038889Sjdp	{
170138889Sjdp	  s = "MENU";
170238889Sjdp	  menuex = 0;
170338889Sjdp	}
170438889Sjdp      rt = RT_MENU;
170538889Sjdp      break;
170638889Sjdp
170738889Sjdp    case RES_TYPE_MESSAGETABLE:
170838889Sjdp      s = "MESSAGETABLE";
170938889Sjdp      rt = RT_MESSAGETABLE;
171038889Sjdp      break;
171138889Sjdp
171238889Sjdp    case RES_TYPE_RCDATA:
171338889Sjdp      s = "RCDATA";
171438889Sjdp      rt = RT_RCDATA;
171538889Sjdp      break;
171638889Sjdp
171738889Sjdp    case RES_TYPE_STRINGTABLE:
171838889Sjdp      s = "STRINGTABLE";
171938889Sjdp      rt = RT_STRING;
172038889Sjdp      break;
172138889Sjdp
172238889Sjdp    case RES_TYPE_USERDATA:
172338889Sjdp      s = NULL;
172438889Sjdp      rt = 0;
172538889Sjdp      break;
172638889Sjdp
172738889Sjdp    case RES_TYPE_VERSIONINFO:
172838889Sjdp      s = "VERSIONINFO";
172938889Sjdp      rt = RT_VERSION;
173038889Sjdp      break;
173138889Sjdp    }
173238889Sjdp
173338889Sjdp  if (rt != 0
173438889Sjdp      && type != NULL
173560484Sobrien      && (type->named || type->u.id != (unsigned long) rt))
173638889Sjdp    {
173738889Sjdp      fprintf (e, "// Unexpected resource type mismatch: ");
173838889Sjdp      res_id_print (e, *type, 1);
173938889Sjdp      fprintf (e, " != %d", rt);
174038889Sjdp    }
174138889Sjdp
174238889Sjdp  if (res->coff_info.codepage != 0)
174338889Sjdp    fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
174438889Sjdp  if (res->coff_info.reserved != 0)
174538889Sjdp    fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
174638889Sjdp
174738889Sjdp  if (name != NULL)
174838889Sjdp    res_id_print (e, *name, 0);
174938889Sjdp  else
175038889Sjdp    fprintf (e, "??Unknown-Name??");
175138889Sjdp
175238889Sjdp  fprintf (e, " ");
175338889Sjdp  if (s != NULL)
175438889Sjdp    fprintf (e, "%s", s);
175538889Sjdp  else if (type != NULL)
175638889Sjdp    res_id_print (e, *type, 0);
175738889Sjdp  else
175838889Sjdp    fprintf (e, "??Unknown-Type??");
175938889Sjdp
176038889Sjdp  if (res->res_info.memflags != 0)
176138889Sjdp    {
176238889Sjdp      if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
176338889Sjdp	fprintf (e, " MOVEABLE");
176438889Sjdp      if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
176538889Sjdp	fprintf (e, " PURE");
176638889Sjdp      if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
176738889Sjdp	fprintf (e, " PRELOAD");
176838889Sjdp      if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
176938889Sjdp	fprintf (e, " DISCARDABLE");
177038889Sjdp    }
177138889Sjdp
177238889Sjdp  if (res->type == RES_TYPE_DIALOG)
177338889Sjdp    {
177438889Sjdp      fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
177538889Sjdp	       res->u.dialog->width, res->u.dialog->height);
177638889Sjdp      if (res->u.dialog->ex != NULL
177738889Sjdp	  && res->u.dialog->ex->help != 0)
177838889Sjdp	fprintf (e, ", %lu", res->u.dialog->ex->help);
177938889Sjdp    }
178038889Sjdp
178138889Sjdp  fprintf (e, "\n");
178238889Sjdp
178338889Sjdp  if ((res->res_info.language != 0 && res->res_info.language != *language)
178438889Sjdp      || res->res_info.characteristics != 0
178538889Sjdp      || res->res_info.version != 0)
178638889Sjdp    {
178738889Sjdp      int modifiers;
178838889Sjdp
178938889Sjdp      switch (res->type)
179038889Sjdp	{
179138889Sjdp	case RES_TYPE_ACCELERATOR:
179238889Sjdp	case RES_TYPE_DIALOG:
179338889Sjdp	case RES_TYPE_MENU:
179438889Sjdp	case RES_TYPE_RCDATA:
179538889Sjdp	case RES_TYPE_STRINGTABLE:
179638889Sjdp	  modifiers = 1;
179738889Sjdp	  break;
179838889Sjdp
179938889Sjdp	default:
180038889Sjdp	  modifiers = 0;
180138889Sjdp	  break;
180238889Sjdp	}
180338889Sjdp
180438889Sjdp      if (res->res_info.language != 0 && res->res_info.language != *language)
180538889Sjdp	fprintf (e, "%sLANGUAGE %d, %d\n",
180638889Sjdp		 modifiers ? "// " : "",
180789857Sobrien		 res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
180889857Sobrien		 (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
180938889Sjdp      if (res->res_info.characteristics != 0)
181038889Sjdp	fprintf (e, "%sCHARACTERISTICS %lu\n",
181138889Sjdp		 modifiers ? "// " : "",
181238889Sjdp		 res->res_info.characteristics);
181338889Sjdp      if (res->res_info.version != 0)
181438889Sjdp	fprintf (e, "%sVERSION %lu\n",
181538889Sjdp		 modifiers ? "// " : "",
181638889Sjdp		 res->res_info.version);
181738889Sjdp    }
181838889Sjdp
181938889Sjdp  switch (res->type)
182038889Sjdp    {
182138889Sjdp    default:
182238889Sjdp      abort ();
182338889Sjdp
182438889Sjdp    case RES_TYPE_ACCELERATOR:
182538889Sjdp      write_rc_accelerators (e, res->u.acc);
182638889Sjdp      break;
182738889Sjdp
182838889Sjdp    case RES_TYPE_CURSOR:
182938889Sjdp      write_rc_cursor (e, res->u.cursor);
183038889Sjdp      break;
183138889Sjdp
183238889Sjdp    case RES_TYPE_GROUP_CURSOR:
183338889Sjdp      write_rc_group_cursor (e, res->u.group_cursor);
183438889Sjdp      break;
183538889Sjdp
183638889Sjdp    case RES_TYPE_DIALOG:
183738889Sjdp      write_rc_dialog (e, res->u.dialog);
183838889Sjdp      break;
183938889Sjdp
184038889Sjdp    case RES_TYPE_FONTDIR:
184138889Sjdp      write_rc_fontdir (e, res->u.fontdir);
184238889Sjdp      break;
184338889Sjdp
184438889Sjdp    case RES_TYPE_GROUP_ICON:
184538889Sjdp      write_rc_group_icon (e, res->u.group_icon);
184638889Sjdp      break;
184738889Sjdp
184838889Sjdp    case RES_TYPE_MENU:
184938889Sjdp      write_rc_menu (e, res->u.menu, menuex);
185038889Sjdp      break;
185138889Sjdp
185238889Sjdp    case RES_TYPE_RCDATA:
185338889Sjdp      write_rc_rcdata (e, res->u.rcdata, 0);
185438889Sjdp      break;
185538889Sjdp
185638889Sjdp    case RES_TYPE_STRINGTABLE:
185738889Sjdp      write_rc_stringtable (e, name, res->u.stringtable);
185838889Sjdp      break;
185938889Sjdp
186038889Sjdp    case RES_TYPE_USERDATA:
186138889Sjdp      write_rc_rcdata (e, res->u.userdata, 0);
186238889Sjdp      break;
186338889Sjdp
186438889Sjdp    case RES_TYPE_VERSIONINFO:
186538889Sjdp      write_rc_versioninfo (e, res->u.versioninfo);
186638889Sjdp      break;
186738889Sjdp
186838889Sjdp    case RES_TYPE_BITMAP:
186938889Sjdp    case RES_TYPE_FONT:
187038889Sjdp    case RES_TYPE_ICON:
187138889Sjdp    case RES_TYPE_MESSAGETABLE:
187238889Sjdp      write_rc_filedata (e, res->u.data.length, res->u.data.data);
187338889Sjdp      break;
187438889Sjdp    }
187538889Sjdp}
187638889Sjdp
187738889Sjdp/* Write out accelerator information.  */
187838889Sjdp
187938889Sjdpstatic void
1880130561Sobrienwrite_rc_accelerators (FILE *e, const struct accelerator *accelerators)
188138889Sjdp{
188238889Sjdp  const struct accelerator *acc;
188338889Sjdp
188438889Sjdp  fprintf (e, "BEGIN\n");
188538889Sjdp  for (acc = accelerators; acc != NULL; acc = acc->next)
188638889Sjdp    {
188738889Sjdp      int printable;
188838889Sjdp
188938889Sjdp      fprintf (e, "  ");
189038889Sjdp
189138889Sjdp      if ((acc->key & 0x7f) == acc->key
189289857Sobrien	  && ISPRINT (acc->key)
189338889Sjdp	  && (acc->flags & ACC_VIRTKEY) == 0)
189438889Sjdp	{
189538889Sjdp	  fprintf (e, "\"%c\"", acc->key);
189638889Sjdp	  printable = 1;
189738889Sjdp	}
189838889Sjdp      else
189938889Sjdp	{
190038889Sjdp	  fprintf (e, "%d", acc->key);
190138889Sjdp	  printable = 0;
190238889Sjdp	}
190338889Sjdp
190438889Sjdp      fprintf (e, ", %d", acc->id);
190538889Sjdp
190638889Sjdp      if (! printable)
190738889Sjdp	{
190838889Sjdp	  if ((acc->flags & ACC_VIRTKEY) != 0)
190938889Sjdp	    fprintf (e, ", VIRTKEY");
191038889Sjdp	  else
191138889Sjdp	    fprintf (e, ", ASCII");
191238889Sjdp	}
191338889Sjdp
191438889Sjdp      if ((acc->flags & ACC_SHIFT) != 0)
191538889Sjdp	fprintf (e, ", SHIFT");
191638889Sjdp      if ((acc->flags & ACC_CONTROL) != 0)
191738889Sjdp	fprintf (e, ", CONTROL");
191838889Sjdp      if ((acc->flags & ACC_ALT) != 0)
191938889Sjdp	fprintf (e, ", ALT");
192038889Sjdp
192138889Sjdp      fprintf (e, "\n");
192238889Sjdp    }
192338889Sjdp
192438889Sjdp  fprintf (e, "END\n");
192538889Sjdp}
192638889Sjdp
192738889Sjdp/* Write out cursor information.  This would normally be in a separate
192838889Sjdp   file, which the rc file would include.  */
192938889Sjdp
193038889Sjdpstatic void
1931130561Sobrienwrite_rc_cursor (FILE *e, const struct cursor *cursor)
193238889Sjdp{
193338889Sjdp  fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
193438889Sjdp	   cursor->yhotspot);
193538889Sjdp  write_rc_filedata (e, cursor->length, cursor->data);
193638889Sjdp}
193738889Sjdp
193838889Sjdp/* Write out group cursor data.  This would normally be built from the
193938889Sjdp   cursor data.  */
194038889Sjdp
194138889Sjdpstatic void
1942130561Sobrienwrite_rc_group_cursor (FILE *e, const struct group_cursor *group_cursor)
194338889Sjdp{
194438889Sjdp  const struct group_cursor *gc;
194538889Sjdp
194638889Sjdp  for (gc = group_cursor; gc != NULL; gc = gc->next)
194738889Sjdp    {
194838889Sjdp      fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
194938889Sjdp	     gc->width, gc->height, gc->planes, gc->bits);
195038889Sjdp      fprintf (e, "// data bytes: %lu; index: %d\n",
195138889Sjdp	       gc->bytes, gc->index);
195238889Sjdp    }
195338889Sjdp}
195438889Sjdp
195538889Sjdp/* Write dialog data.  */
195638889Sjdp
195738889Sjdpstatic void
1958130561Sobrienwrite_rc_dialog (FILE *e, const struct dialog *dialog)
195938889Sjdp{
196038889Sjdp  const struct dialog_control *control;
196138889Sjdp
196299461Sobrien  fprintf (e, "STYLE 0x%lx\n", dialog->style);
196399461Sobrien
196438889Sjdp  if (dialog->exstyle != 0)
196538889Sjdp    fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
196699461Sobrien
196738889Sjdp  if ((dialog->class.named && dialog->class.u.n.length > 0)
196838889Sjdp      || dialog->class.u.id != 0)
196938889Sjdp    {
197038889Sjdp      fprintf (e, "CLASS ");
197199461Sobrien      res_id_print (e, dialog->class, 1);
197238889Sjdp      fprintf (e, "\n");
197338889Sjdp    }
197499461Sobrien
197538889Sjdp  if (dialog->caption != NULL)
197638889Sjdp    {
197738889Sjdp      fprintf (e, "CAPTION \"");
197838889Sjdp      unicode_print (e, dialog->caption, -1);
197938889Sjdp      fprintf (e, "\"\n");
198038889Sjdp    }
198199461Sobrien
198238889Sjdp  if ((dialog->menu.named && dialog->menu.u.n.length > 0)
198338889Sjdp      || dialog->menu.u.id != 0)
198438889Sjdp    {
198538889Sjdp      fprintf (e, "MENU ");
198638889Sjdp      res_id_print (e, dialog->menu, 0);
198738889Sjdp      fprintf (e, "\n");
198838889Sjdp    }
198999461Sobrien
199038889Sjdp  if (dialog->font != NULL)
199138889Sjdp    {
199238889Sjdp      fprintf (e, "FONT %d, \"", dialog->pointsize);
199338889Sjdp      unicode_print (e, dialog->font, -1);
199438889Sjdp      fprintf (e, "\"");
199538889Sjdp      if (dialog->ex != NULL
199699461Sobrien	  && (dialog->ex->weight != 0
199799461Sobrien	      || dialog->ex->italic != 0
199899461Sobrien	      || dialog->ex->charset != 1))
199999461Sobrien	fprintf (e, ", %d, %d, %d",
200099461Sobrien		 dialog->ex->weight, dialog->ex->italic, dialog->ex->charset);
200138889Sjdp      fprintf (e, "\n");
200238889Sjdp    }
200338889Sjdp
200438889Sjdp  fprintf (e, "BEGIN\n");
200538889Sjdp
200638889Sjdp  for (control = dialog->controls; control != NULL; control = control->next)
200738889Sjdp    write_rc_dialog_control (e, control);
200838889Sjdp
200938889Sjdp  fprintf (e, "END\n");
201038889Sjdp}
201138889Sjdp
201238889Sjdp/* For each predefined control keyword, this table provides the class
201338889Sjdp   and the style.  */
201438889Sjdp
201538889Sjdpstruct control_info
201638889Sjdp{
201738889Sjdp  const char *name;
201838889Sjdp  unsigned short class;
201938889Sjdp  unsigned long style;
202038889Sjdp};
202138889Sjdp
202238889Sjdpstatic const struct control_info control_info[] =
202338889Sjdp{
202438889Sjdp  { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
202538889Sjdp  { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
202638889Sjdp  { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
202738889Sjdp  { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
202838889Sjdp  { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
202938889Sjdp  { "CTEXT", CTL_STATIC, SS_CENTER },
203038889Sjdp  { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
203138889Sjdp  { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
203238889Sjdp  { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
203338889Sjdp  { "ICON", CTL_STATIC, SS_ICON },
203438889Sjdp  { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
203538889Sjdp  { "LTEXT", CTL_STATIC, SS_LEFT },
203638889Sjdp  { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
203738889Sjdp  { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
203838889Sjdp  { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
203938889Sjdp  { "RTEXT", CTL_STATIC, SS_RIGHT },
204038889Sjdp  { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
204138889Sjdp  { "STATE3", CTL_BUTTON, BS_3STATE },
204238889Sjdp  /* It's important that USERBUTTON come after all the other button
204338889Sjdp     types, so that it won't be matched too early.  */
204438889Sjdp  { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
204538889Sjdp  { NULL, 0, 0 }
204638889Sjdp};
204738889Sjdp
204838889Sjdp/* Write a dialog control.  */
204938889Sjdp
205038889Sjdpstatic void
2051130561Sobrienwrite_rc_dialog_control (FILE *e, const struct dialog_control *control)
205238889Sjdp{
205338889Sjdp  const struct control_info *ci;
205438889Sjdp
205538889Sjdp  fprintf (e, "  ");
205638889Sjdp
205738889Sjdp  if (control->class.named)
205838889Sjdp    ci = NULL;
205938889Sjdp  else
206038889Sjdp    {
206138889Sjdp      for (ci = control_info; ci->name != NULL; ++ci)
206238889Sjdp	if (ci->class == control->class.u.id
206338889Sjdp	    && (ci->style == (unsigned long) -1
206438889Sjdp		|| ci->style == (control->style & 0xff)))
206538889Sjdp	  break;
206638889Sjdp    }
206760484Sobrien  if (ci == NULL)
206860484Sobrien    fprintf (e, "CONTROL");
206960484Sobrien  else if (ci->name != NULL)
207038889Sjdp    fprintf (e, "%s", ci->name);
207138889Sjdp  else
207238889Sjdp    fprintf (e, "CONTROL");
2073104834Sobrien
207438889Sjdp  if (control->text.named || control->text.u.id != 0)
207538889Sjdp    {
207638889Sjdp      fprintf (e, " ");
207738889Sjdp      res_id_print (e, control->text, 1);
207838889Sjdp      fprintf (e, ",");
207938889Sjdp    }
208038889Sjdp
208138889Sjdp  fprintf (e, " %d, ", control->id);
208238889Sjdp
208360484Sobrien  if (ci == NULL)
208438889Sjdp    {
208560484Sobrien      if (control->class.named)
208660484Sobrien	fprintf (e, "\"");
208738889Sjdp      res_id_print (e, control->class, 0);
208860484Sobrien      if (control->class.named)
208960484Sobrien	fprintf (e, "\"");
209038889Sjdp      fprintf (e, ", 0x%lx, ", control->style);
209138889Sjdp    }
209238889Sjdp
209338889Sjdp  fprintf (e, "%d, %d", control->x, control->y);
209438889Sjdp
209538889Sjdp  if (control->style != SS_ICON
209638889Sjdp      || control->exstyle != 0
209738889Sjdp      || control->width != 0
209838889Sjdp      || control->height != 0
209938889Sjdp      || control->help != 0)
210038889Sjdp    {
210138889Sjdp      fprintf (e, ", %d, %d", control->width, control->height);
210238889Sjdp
210338889Sjdp      /* FIXME: We don't need to print the style if it is the default.
210438889Sjdp	 More importantly, in certain cases we actually need to turn
210538889Sjdp	 off parts of the forced style, by using NOT.  */
210638889Sjdp      fprintf (e, ", 0x%lx", control->style);
210738889Sjdp
210838889Sjdp      if (control->exstyle != 0 || control->help != 0)
210938889Sjdp	fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
211038889Sjdp    }
211138889Sjdp
211238889Sjdp  fprintf (e, "\n");
211338889Sjdp
211438889Sjdp  if (control->data != NULL)
211538889Sjdp    write_rc_rcdata (e, control->data, 2);
211638889Sjdp}
211738889Sjdp
211838889Sjdp/* Write out font directory data.  This would normally be built from
211938889Sjdp   the font data.  */
212038889Sjdp
212138889Sjdpstatic void
2122130561Sobrienwrite_rc_fontdir (FILE *e, const struct fontdir *fontdir)
212338889Sjdp{
212438889Sjdp  const struct fontdir *fc;
212538889Sjdp
212638889Sjdp  for (fc = fontdir; fc != NULL; fc = fc->next)
212738889Sjdp    {
212838889Sjdp      fprintf (e, "// Font index: %d\n", fc->index);
212938889Sjdp      write_rc_filedata (e, fc->length, fc->data);
213038889Sjdp    }
213138889Sjdp}
213238889Sjdp
213338889Sjdp/* Write out group icon data.  This would normally be built from the
213438889Sjdp   icon data.  */
213538889Sjdp
213638889Sjdpstatic void
2137130561Sobrienwrite_rc_group_icon (FILE *e, const struct group_icon *group_icon)
213838889Sjdp{
213938889Sjdp  const struct group_icon *gi;
214038889Sjdp
214138889Sjdp  for (gi = group_icon; gi != NULL; gi = gi->next)
214238889Sjdp    {
214338889Sjdp      fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
214438889Sjdp	       gi->width, gi->height, gi->colors, gi->planes, gi->bits);
214538889Sjdp      fprintf (e, "// data bytes: %lu; index: %d\n",
214638889Sjdp	       gi->bytes, gi->index);
214738889Sjdp    }
214838889Sjdp}
214938889Sjdp
215038889Sjdp/* Write out a menu resource.  */
215138889Sjdp
215238889Sjdpstatic void
2153130561Sobrienwrite_rc_menu (FILE *e, const struct menu *menu, int menuex)
215438889Sjdp{
215538889Sjdp  if (menu->help != 0)
215638889Sjdp    fprintf (e, "// Help ID: %lu\n", menu->help);
215738889Sjdp  write_rc_menuitems (e, menu->items, menuex, 0);
215838889Sjdp}
215938889Sjdp
216038889Sjdp/* Write out menuitems.  */
216138889Sjdp
216238889Sjdpstatic void
2163130561Sobrienwrite_rc_menuitems (FILE *e, const struct menuitem *menuitems, int menuex,
2164130561Sobrien		    int ind)
216538889Sjdp{
216638889Sjdp  const struct menuitem *mi;
216738889Sjdp
216838889Sjdp  indent (e, ind);
216938889Sjdp  fprintf (e, "BEGIN\n");
217038889Sjdp
217138889Sjdp  for (mi = menuitems; mi != NULL; mi = mi->next)
217238889Sjdp    {
217338889Sjdp      indent (e, ind + 2);
217438889Sjdp
217538889Sjdp      if (mi->popup == NULL)
217638889Sjdp	fprintf (e, "MENUITEM");
217738889Sjdp      else
217838889Sjdp	fprintf (e, "POPUP");
217938889Sjdp
218038889Sjdp      if (! menuex
218138889Sjdp	  && mi->popup == NULL
218238889Sjdp	  && mi->text == NULL
218338889Sjdp	  && mi->type == 0
218438889Sjdp	  && mi->id == 0)
218538889Sjdp	{
218638889Sjdp	  fprintf (e, " SEPARATOR\n");
218738889Sjdp	  continue;
218838889Sjdp	}
218938889Sjdp
219038889Sjdp      if (mi->text == NULL)
219138889Sjdp	fprintf (e, " \"\"");
219238889Sjdp      else
219338889Sjdp	{
219438889Sjdp	  fprintf (e, " \"");
219538889Sjdp	  unicode_print (e, mi->text, -1);
219638889Sjdp	  fprintf (e, "\"");
219738889Sjdp	}
219838889Sjdp
219938889Sjdp      if (! menuex)
220038889Sjdp	{
220138889Sjdp	  if (mi->popup == NULL)
220238889Sjdp	    fprintf (e, ", %d", mi->id);
220338889Sjdp
220438889Sjdp	  if ((mi->type & MENUITEM_CHECKED) != 0)
220538889Sjdp	    fprintf (e, ", CHECKED");
220638889Sjdp	  if ((mi->type & MENUITEM_GRAYED) != 0)
220738889Sjdp	    fprintf (e, ", GRAYED");
220838889Sjdp	  if ((mi->type & MENUITEM_HELP) != 0)
220938889Sjdp	    fprintf (e, ", HELP");
221038889Sjdp	  if ((mi->type & MENUITEM_INACTIVE) != 0)
221138889Sjdp	    fprintf (e, ", INACTIVE");
221238889Sjdp	  if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
221338889Sjdp	    fprintf (e, ", MENUBARBREAK");
221438889Sjdp	  if ((mi->type & MENUITEM_MENUBREAK) != 0)
221538889Sjdp	    fprintf (e, ", MENUBREAK");
221638889Sjdp	}
221738889Sjdp      else
221838889Sjdp	{
221938889Sjdp	  if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
222038889Sjdp	    {
222138889Sjdp	      fprintf (e, ", %d", mi->id);
222238889Sjdp	      if (mi->type != 0 || mi->state != 0 || mi->help != 0)
222338889Sjdp		{
222438889Sjdp		  fprintf (e, ", %lu", mi->type);
222538889Sjdp		  if (mi->state != 0 || mi->help != 0)
222638889Sjdp		    {
222738889Sjdp		      fprintf (e, ", %lu", mi->state);
222838889Sjdp		      if (mi->help != 0)
222938889Sjdp			fprintf (e, ", %lu", mi->help);
223038889Sjdp		    }
223138889Sjdp		}
223238889Sjdp	    }
223338889Sjdp	}
223438889Sjdp
223538889Sjdp      fprintf (e, "\n");
223638889Sjdp
223738889Sjdp      if (mi->popup != NULL)
223838889Sjdp	write_rc_menuitems (e, mi->popup, menuex, ind + 2);
223938889Sjdp    }
224038889Sjdp
224138889Sjdp  indent (e, ind);
224238889Sjdp  fprintf (e, "END\n");
224338889Sjdp}
224438889Sjdp
224538889Sjdp/* Write out an rcdata resource.  This is also used for other types of
224638889Sjdp   resources that need to print arbitrary data.  */
224738889Sjdp
224838889Sjdpstatic void
2249130561Sobrienwrite_rc_rcdata (FILE *e, const struct rcdata_item *rcdata, int ind)
225038889Sjdp{
225138889Sjdp  const struct rcdata_item *ri;
225238889Sjdp
225338889Sjdp  indent (e, ind);
225438889Sjdp  fprintf (e, "BEGIN\n");
225538889Sjdp
225638889Sjdp  for (ri = rcdata; ri != NULL; ri = ri->next)
225738889Sjdp    {
225838889Sjdp      if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
225938889Sjdp	continue;
226038889Sjdp
226138889Sjdp      indent (e, ind + 2);
226238889Sjdp
226338889Sjdp      switch (ri->type)
226438889Sjdp	{
226538889Sjdp	default:
226638889Sjdp	  abort ();
226738889Sjdp
226838889Sjdp	case RCDATA_WORD:
226938889Sjdp	  fprintf (e, "%d", ri->u.word);
227038889Sjdp	  break;
227138889Sjdp
227238889Sjdp	case RCDATA_DWORD:
227338889Sjdp	  fprintf (e, "%luL", ri->u.dword);
227438889Sjdp	  break;
227538889Sjdp
227638889Sjdp	case RCDATA_STRING:
227738889Sjdp	  {
227838889Sjdp	    const char *s;
227938889Sjdp	    unsigned long i;
228038889Sjdp
228138889Sjdp	    fprintf (e, "\"");
228238889Sjdp	    s = ri->u.string.s;
228338889Sjdp	    for (i = 0; i < ri->u.string.length; i++)
228438889Sjdp	      {
228589857Sobrien		if (ISPRINT (*s))
228638889Sjdp		  putc (*s, e);
228738889Sjdp		else
228838889Sjdp		  fprintf (e, "\\%03o", *s);
228938889Sjdp	      }
229038889Sjdp	    fprintf (e, "\"");
229138889Sjdp	    break;
229238889Sjdp	  }
229338889Sjdp
229438889Sjdp	case RCDATA_WSTRING:
229538889Sjdp	  fprintf (e, "L\"");
229638889Sjdp	  unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
229738889Sjdp	  fprintf (e, "\"");
229838889Sjdp	  break;
229938889Sjdp
230038889Sjdp	case RCDATA_BUFFER:
230138889Sjdp	  {
230238889Sjdp	    unsigned long i;
230338889Sjdp	    int first;
230438889Sjdp
230538889Sjdp	    /* Assume little endian data.  */
230638889Sjdp
230738889Sjdp	    first = 1;
230838889Sjdp	    for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
230938889Sjdp	      {
231038889Sjdp		unsigned long l;
231160484Sobrien		int j;
231238889Sjdp
231360484Sobrien		if (! first)
231460484Sobrien		  indent (e, ind + 2);
231538889Sjdp		l = ((((((ri->u.buffer.data[i + 3] << 8)
231638889Sjdp			 | ri->u.buffer.data[i + 2]) << 8)
231738889Sjdp		       | ri->u.buffer.data[i + 1]) << 8)
231838889Sjdp		     | ri->u.buffer.data[i]);
231960484Sobrien		fprintf (e, "%luL", l);
232060484Sobrien		if (i + 4 < ri->u.buffer.length || ri->next != NULL)
232160484Sobrien		  fprintf (e, ",");
232260484Sobrien		for (j = 0; j < 4; ++j)
232389857Sobrien		  if (! ISPRINT (ri->u.buffer.data[i + j])
232460484Sobrien		      && ri->u.buffer.data[i + j] != 0)
232560484Sobrien		    break;
232660484Sobrien		if (j >= 4)
232738889Sjdp		  {
232860484Sobrien		    fprintf (e, "\t// ");
232960484Sobrien		    for (j = 0; j < 4; ++j)
233060484Sobrien		      {
233189857Sobrien			if (! ISPRINT (ri->u.buffer.data[i + j]))
233260484Sobrien			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
233360484Sobrien			else
233460484Sobrien			  {
233560484Sobrien			    if (ri->u.buffer.data[i + j] == '\\')
233660484Sobrien			      fprintf (e, "\\");
233760484Sobrien			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
233860484Sobrien			  }
233960484Sobrien		      }
234038889Sjdp		  }
234160484Sobrien		fprintf (e, "\n");
234260484Sobrien		first = 0;
234338889Sjdp	      }
234438889Sjdp
234538889Sjdp	    if (i + 1 < ri->u.buffer.length)
234638889Sjdp	      {
234760484Sobrien		int s;
234860484Sobrien		int j;
234938889Sjdp
235060484Sobrien		if (! first)
235160484Sobrien		  indent (e, ind + 2);
235260484Sobrien		s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
235360484Sobrien		fprintf (e, "%d", s);
235460484Sobrien		if (i + 2 < ri->u.buffer.length || ri->next != NULL)
235560484Sobrien		  fprintf (e, ",");
235660484Sobrien		for (j = 0; j < 2; ++j)
235789857Sobrien		  if (! ISPRINT (ri->u.buffer.data[i + j])
235860484Sobrien		      && ri->u.buffer.data[i + j] != 0)
235960484Sobrien		    break;
236060484Sobrien		if (j >= 2)
236138889Sjdp		  {
236260484Sobrien		    fprintf (e, "\t// ");
236360484Sobrien		    for (j = 0; j < 2; ++j)
236460484Sobrien		      {
236589857Sobrien			if (! ISPRINT (ri->u.buffer.data[i + j]))
236660484Sobrien			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
236760484Sobrien			else
236860484Sobrien			  {
236960484Sobrien			    if (ri->u.buffer.data[i + j] == '\\')
237060484Sobrien			      fprintf (e, "\\");
237160484Sobrien			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
237260484Sobrien			  }
237360484Sobrien		      }
237438889Sjdp		  }
237560484Sobrien		fprintf (e, "\n");
237638889Sjdp		i += 2;
237760484Sobrien		first = 0;
237838889Sjdp	      }
237938889Sjdp
238038889Sjdp	    if (i < ri->u.buffer.length)
238138889Sjdp	      {
238260484Sobrien		if (! first)
238360484Sobrien		  indent (e, ind + 2);
238438889Sjdp		if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
238589857Sobrien		    && ISPRINT (ri->u.buffer.data[i]))
238638889Sjdp		  fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
238738889Sjdp		else
238860484Sobrien		  fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
238960484Sobrien		if (ri->next != NULL)
239060484Sobrien		  fprintf (e, ",");
239160484Sobrien		fprintf (e, "\n");
239260484Sobrien		first = 0;
239338889Sjdp	      }
239438889Sjdp
239538889Sjdp	    break;
239638889Sjdp	  }
239738889Sjdp	}
239838889Sjdp
239960484Sobrien      if (ri->type != RCDATA_BUFFER)
240060484Sobrien	{
240160484Sobrien	  if (ri->next != NULL)
240260484Sobrien	    fprintf (e, ",");
240360484Sobrien	  fprintf (e, "\n");
240460484Sobrien	}
240538889Sjdp    }
240638889Sjdp
240738889Sjdp  indent (e, ind);
240838889Sjdp  fprintf (e, "END\n");
240938889Sjdp}
241038889Sjdp
241138889Sjdp/* Write out a stringtable resource.  */
241238889Sjdp
241338889Sjdpstatic void
2414130561Sobrienwrite_rc_stringtable (FILE *e, const struct res_id *name,
2415130561Sobrien		      const struct stringtable *stringtable)
241638889Sjdp{
241738889Sjdp  unsigned long offset;
241838889Sjdp  int i;
241938889Sjdp
242038889Sjdp  if (name != NULL && ! name->named)
242138889Sjdp    offset = (name->u.id - 1) << 4;
242238889Sjdp  else
242338889Sjdp    {
242438889Sjdp      fprintf (e, "// %s string table name\n",
242538889Sjdp	       name == NULL ? "Missing" : "Invalid");
242638889Sjdp      offset = 0;
242738889Sjdp    }
242838889Sjdp
242938889Sjdp  fprintf (e, "BEGIN\n");
243038889Sjdp
243138889Sjdp  for (i = 0; i < 16; i++)
243238889Sjdp    {
243338889Sjdp      if (stringtable->strings[i].length != 0)
243438889Sjdp	{
243538889Sjdp	  fprintf (e, "  %lu, \"", offset + i);
243638889Sjdp	  unicode_print (e, stringtable->strings[i].string,
243738889Sjdp			 stringtable->strings[i].length);
243838889Sjdp	  fprintf (e, "\"\n");
243938889Sjdp	}
244038889Sjdp    }
244138889Sjdp
244238889Sjdp  fprintf (e, "END\n");
244338889Sjdp}
244438889Sjdp
244538889Sjdp/* Write out a versioninfo resource.  */
244638889Sjdp
244738889Sjdpstatic void
2448130561Sobrienwrite_rc_versioninfo (FILE *e, const struct versioninfo *versioninfo)
244938889Sjdp{
245038889Sjdp  const struct fixed_versioninfo *f;
245138889Sjdp  const struct ver_info *vi;
245238889Sjdp
245338889Sjdp  f = versioninfo->fixed;
245438889Sjdp  if (f->file_version_ms != 0 || f->file_version_ls != 0)
245538889Sjdp    fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
245638889Sjdp	     (f->file_version_ms >> 16) & 0xffff,
245738889Sjdp	     f->file_version_ms & 0xffff,
245838889Sjdp	     (f->file_version_ls >> 16) & 0xffff,
245938889Sjdp	     f->file_version_ls & 0xffff);
246038889Sjdp  if (f->product_version_ms != 0 || f->product_version_ls != 0)
246138889Sjdp    fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
246238889Sjdp	     (f->product_version_ms >> 16) & 0xffff,
246338889Sjdp	     f->product_version_ms & 0xffff,
246438889Sjdp	     (f->product_version_ls >> 16) & 0xffff,
246538889Sjdp	     f->product_version_ls & 0xffff);
246638889Sjdp  if (f->file_flags_mask != 0)
246738889Sjdp    fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
246838889Sjdp  if (f->file_flags != 0)
246938889Sjdp    fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
247038889Sjdp  if (f->file_os != 0)
247138889Sjdp    fprintf (e, " FILEOS 0x%lx\n", f->file_os);
247238889Sjdp  if (f->file_type != 0)
247338889Sjdp    fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
247438889Sjdp  if (f->file_subtype != 0)
247538889Sjdp    fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
247638889Sjdp  if (f->file_date_ms != 0 || f->file_date_ls != 0)
247738889Sjdp    fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
247838889Sjdp
247938889Sjdp  fprintf (e, "BEGIN\n");
248038889Sjdp
248138889Sjdp  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
248238889Sjdp    {
248338889Sjdp      switch (vi->type)
248438889Sjdp	{
248538889Sjdp	case VERINFO_STRING:
248638889Sjdp	  {
248738889Sjdp	    const struct ver_stringinfo *vs;
248838889Sjdp
248938889Sjdp	    fprintf (e, "  BLOCK \"StringFileInfo\"\n");
249038889Sjdp	    fprintf (e, "  BEGIN\n");
249138889Sjdp	    fprintf (e, "    BLOCK \"");
249238889Sjdp	    unicode_print (e, vi->u.string.language, -1);
249338889Sjdp	    fprintf (e, "\"\n");
249438889Sjdp	    fprintf (e, "    BEGIN\n");
249538889Sjdp
249638889Sjdp	    for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
249738889Sjdp	      {
249838889Sjdp		fprintf (e, "      VALUE \"");
249938889Sjdp		unicode_print (e, vs->key, -1);
250038889Sjdp		fprintf (e, "\", \"");
250138889Sjdp		unicode_print (e, vs->value, -1);
250238889Sjdp		fprintf (e, "\"\n");
250338889Sjdp	      }
250438889Sjdp
250538889Sjdp	    fprintf (e, "    END\n");
250638889Sjdp	    fprintf (e, "  END\n");
250738889Sjdp	    break;
250838889Sjdp	  }
250938889Sjdp
251038889Sjdp	case VERINFO_VAR:
251138889Sjdp	  {
251238889Sjdp	    const struct ver_varinfo *vv;
251338889Sjdp
251438889Sjdp	    fprintf (e, "  BLOCK \"VarFileInfo\"\n");
251538889Sjdp	    fprintf (e, "  BEGIN\n");
251638889Sjdp	    fprintf (e, "    VALUE \"");
251738889Sjdp	    unicode_print (e, vi->u.var.key, -1);
251838889Sjdp	    fprintf (e, "\"");
251938889Sjdp
252038889Sjdp	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
252138889Sjdp	      fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
252238889Sjdp		       vv->charset);
252338889Sjdp
252438889Sjdp	    fprintf (e, "\n  END\n");
252538889Sjdp
252638889Sjdp	    break;
252738889Sjdp	  }
252838889Sjdp	}
252938889Sjdp    }
253038889Sjdp
253138889Sjdp  fprintf (e, "END\n");
253238889Sjdp}
253338889Sjdp
253438889Sjdp/* Write out data which would normally be read from a file.  */
253538889Sjdp
253638889Sjdpstatic void
2537130561Sobrienwrite_rc_filedata (FILE *e, unsigned long length, const unsigned char *data)
253838889Sjdp{
253938889Sjdp  unsigned long i;
254038889Sjdp
254138889Sjdp  for (i = 0; i + 15 < length; i += 16)
254238889Sjdp    {
254338889Sjdp      fprintf (e, "// %4lx: ", i);
254438889Sjdp      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
254538889Sjdp	       data[i + 0], data[i + 1], data[i + 2], data[i + 3],
254638889Sjdp	       data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
254738889Sjdp      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
254838889Sjdp	       data[i +  8], data[i +  9], data[i + 10], data[i + 11],
254938889Sjdp	       data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
255038889Sjdp    }
255138889Sjdp
255238889Sjdp  if (i < length)
255338889Sjdp    {
255438889Sjdp      fprintf (e, "// %4lx:", i);
255538889Sjdp      while (i < length)
255638889Sjdp	{
255738889Sjdp	  fprintf (e, " %02x", data[i]);
255838889Sjdp	  ++i;
255938889Sjdp	}
256038889Sjdp      fprintf (e, "\n");
256138889Sjdp    }
256238889Sjdp}
2563