resrc.c revision 1.4
1/* resrc.c -- read and write Windows rc files.
2   Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3   Written by Ian Lance Taylor, Cygnus Support.
4
5   This file is part of GNU Binutils.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20   02111-1307, USA.  */
21
22/* This file contains functions that read and write Windows rc files.
23   These are text files that represent resources.  */
24
25#include "bfd.h"
26#include "bucomm.h"
27#include "libiberty.h"
28#include "safe-ctype.h"
29#include "windres.h"
30
31#include <assert.h>
32#include <errno.h>
33#include <sys/stat.h>
34#ifdef HAVE_UNISTD_H
35#include <unistd.h>
36#endif
37
38#ifdef HAVE_SYS_WAIT_H
39#include <sys/wait.h>
40#else /* ! HAVE_SYS_WAIT_H */
41#if ! defined (_WIN32) || defined (__CYGWIN__)
42#ifndef WIFEXITED
43#define WIFEXITED(w)	(((w)&0377) == 0)
44#endif
45#ifndef WIFSIGNALED
46#define WIFSIGNALED(w)	(((w)&0377) != 0177 && ((w)&~0377) == 0)
47#endif
48#ifndef WTERMSIG
49#define WTERMSIG(w)	((w) & 0177)
50#endif
51#ifndef WEXITSTATUS
52#define WEXITSTATUS(w)	(((w) >> 8) & 0377)
53#endif
54#else /* defined (_WIN32) && ! defined (__CYGWIN__) */
55#ifndef WIFEXITED
56#define WIFEXITED(w)	(((w) & 0xff) == 0)
57#endif
58#ifndef WIFSIGNALED
59#define WIFSIGNALED(w)	(((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
60#endif
61#ifndef WTERMSIG
62#define WTERMSIG(w)	((w) & 0x7f)
63#endif
64#ifndef WEXITSTATUS
65#define WEXITSTATUS(w)	(((w) & 0xff00) >> 8)
66#endif
67#endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
68#endif /* ! HAVE_SYS_WAIT_H */
69
70#ifndef STDOUT_FILENO
71#define STDOUT_FILENO 1
72#endif
73
74#if defined (_WIN32) && ! defined (__CYGWIN__)
75#define popen _popen
76#define pclose _pclose
77#endif
78
79/* The default preprocessor.  */
80
81#define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
82
83/* We read the directory entries in a cursor or icon file into
84   instances of this structure.  */
85
86struct icondir
87{
88  /* Width of image.  */
89  unsigned char width;
90  /* Height of image.  */
91  unsigned char height;
92  /* Number of colors in image.  */
93  unsigned char colorcount;
94  union
95  {
96    struct
97    {
98      /* Color planes.  */
99      unsigned short planes;
100      /* Bits per pixel.  */
101      unsigned short bits;
102    } icon;
103    struct
104    {
105      /* X coordinate of hotspot.  */
106      unsigned short xhotspot;
107      /* Y coordinate of hotspot.  */
108      unsigned short yhotspot;
109    } cursor;
110  } u;
111  /* Bytes in image.  */
112  unsigned long bytes;
113  /* File offset of image.  */
114  unsigned long offset;
115};
116
117/* The name of the rc file we are reading.  */
118
119char *rc_filename;
120
121/* The line number in the rc file.  */
122
123int rc_lineno;
124
125/* The pipe we are reading from, so that we can close it if we exit.  */
126
127static FILE *cpp_pipe;
128
129/* The temporary file used if we're not using popen, so we can delete it
130   if we exit.  */
131
132static char *cpp_temp_file;
133
134/* Input stream is either a file or a pipe.  */
135
136static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
137
138/* As we read the rc file, we attach information to this structure.  */
139
140static struct res_directory *resources;
141
142/* The number of cursor resources we have written out.  */
143
144static int cursors;
145
146/* The number of font resources we have written out.  */
147
148static int fonts;
149
150/* Font directory information.  */
151
152struct fontdir *fontdirs;
153
154/* Resource info to use for fontdirs.  */
155
156struct res_res_info fontdirs_resinfo;
157
158/* The number of icon resources we have written out.  */
159
160static int icons;
161
162/* Local functions.  */
163
164static int run_cmd PARAMS ((char *, const char *));
165static FILE *open_input_stream PARAMS ((char *));
166static FILE *look_for_default PARAMS ((char *, const char *, int,
167				       const char *, const char *));
168static void close_input_stream PARAMS ((void));
169static void unexpected_eof PARAMS ((const char *));
170static int get_word PARAMS ((FILE *, const char *));
171static unsigned long get_long PARAMS ((FILE *, const char *));
172static void get_data
173  PARAMS ((FILE *, unsigned char *, unsigned long, const char *));
174static void define_fontdirs PARAMS ((void));
175
176/* Run `cmd' and redirect the output to `redir'.  */
177
178static int
179run_cmd (cmd, redir)
180     char *cmd;
181     const char *redir;
182{
183  char *s;
184  int pid, wait_status, retcode;
185  int i;
186  const char **argv;
187  char *errmsg_fmt, *errmsg_arg;
188#if defined(__MSDOS__) && !defined(__GO32__)
189  char *temp_base = choose_temp_base ();
190#else
191  char *temp_base = NULL;
192#endif
193
194  int in_quote;
195  char sep;
196  int redir_handle = -1;
197  int stdout_save = -1;
198
199  /* Count the args.  */
200  i = 0;
201
202  for (s = cmd; *s; s++)
203    if (*s == ' ')
204      i++;
205
206  i++;
207  argv = alloca (sizeof (char *) * (i + 3));
208  i = 0;
209  s = cmd;
210
211  while (1)
212    {
213      while (*s == ' ' && *s != 0)
214	s++;
215
216      if (*s == 0)
217	break;
218
219      in_quote = (*s == '\'' || *s == '"');
220      sep = (in_quote) ? *s++ : ' ';
221      argv[i++] = s;
222
223      while (*s != sep && *s != 0)
224	s++;
225
226      if (*s == 0)
227	break;
228
229      *s++ = 0;
230
231      if (in_quote)
232	s++;
233    }
234  argv[i++] = NULL;
235
236  /* Setup the redirection.  We can't use the usual fork/exec and redirect
237     since we may be running on non-POSIX Windows host.  */
238
239  fflush (stdout);
240  fflush (stderr);
241
242  /* Open temporary output file.  */
243  redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
244  if (redir_handle == -1)
245    fatal (_("can't open temporary file `%s': %s"), redir,
246	   strerror (errno));
247
248  /* Duplicate the stdout file handle so it can be restored later.  */
249  stdout_save = dup (STDOUT_FILENO);
250  if (stdout_save == -1)
251    fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
252
253  /* Redirect stdout to our output file.  */
254  dup2 (redir_handle, STDOUT_FILENO);
255
256  pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
257		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
258
259  /* Restore stdout to its previous setting.  */
260  dup2 (stdout_save, STDOUT_FILENO);
261
262  /* Close reponse file.  */
263  close (redir_handle);
264
265  if (pid == -1)
266    {
267      fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
268      return 1;
269    }
270
271  retcode = 0;
272  pid = pwait (pid, &wait_status, 0);
273
274  if (pid == -1)
275    {
276      fatal (_("wait: %s"), strerror (errno));
277      retcode = 1;
278    }
279  else if (WIFSIGNALED (wait_status))
280    {
281      fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
282      retcode = 1;
283    }
284  else if (WIFEXITED (wait_status))
285    {
286      if (WEXITSTATUS (wait_status) != 0)
287	{
288	  fatal (_("%s exited with status %d"), cmd,
289	         WEXITSTATUS (wait_status));
290	  retcode = 1;
291	}
292    }
293  else
294    retcode = 1;
295
296  return retcode;
297}
298
299static FILE *
300open_input_stream (cmd)
301     char *cmd;
302{
303  if (istream_type == ISTREAM_FILE)
304    {
305      cpp_temp_file = make_temp_file (".irc");
306
307      if (run_cmd (cmd, cpp_temp_file))
308	fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
309
310      cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
311      if (cpp_pipe == NULL)
312	fatal (_("can't open temporary file `%s': %s"),
313	       cpp_temp_file, strerror (errno));
314
315      if (verbose)
316	fprintf (stderr,
317	         _("Using temporary file `%s' to read preprocessor output\n"),
318		 cpp_temp_file);
319    }
320  else
321    {
322      cpp_pipe = popen (cmd, FOPEN_RT);
323      if (cpp_pipe == NULL)
324	fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
325      if (verbose)
326	fprintf (stderr, _("Using popen to read preprocessor output\n"));
327    }
328
329  xatexit (close_input_stream);
330  return cpp_pipe;
331}
332
333/* look for the preprocessor program */
334
335static FILE *
336look_for_default (cmd, prefix, end_prefix, preprocargs, filename)
337     char *cmd;
338     const char *prefix;
339     int end_prefix;
340     const char *preprocargs;
341     const char *filename;
342{
343  char *space;
344  int found;
345  struct stat s;
346
347  strcpy (cmd, prefix);
348
349  sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
350  space = strchr (cmd + end_prefix, ' ');
351  if (space)
352    *space = 0;
353
354  if (
355#if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
356      strchr (cmd, '\\') ||
357#endif
358      strchr (cmd, '/'))
359    {
360      found = (stat (cmd, &s) == 0
361#ifdef HAVE_EXECUTABLE_SUFFIX
362	       || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
363#endif
364	       );
365
366      if (! found)
367	{
368	  if (verbose)
369	    fprintf (stderr, _("Tried `%s'\n"), cmd);
370	  return NULL;
371	}
372    }
373
374  strcpy (cmd, prefix);
375
376  sprintf (cmd + end_prefix, "%s %s %s",
377	   DEFAULT_PREPROCESSOR, preprocargs, filename);
378
379  if (verbose)
380    fprintf (stderr, _("Using `%s'\n"), cmd);
381
382  cpp_pipe = open_input_stream (cmd);
383  return cpp_pipe;
384}
385
386/* Read an rc file.  */
387
388struct res_directory *
389read_rc_file (filename, preprocessor, preprocargs, language, use_temp_file)
390     const char *filename;
391     const char *preprocessor;
392     const char *preprocargs;
393     int language;
394     int use_temp_file;
395{
396  char *cmd;
397
398  istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
399
400  if (preprocargs == NULL)
401    preprocargs = "";
402  if (filename == NULL)
403    filename = "-";
404
405  if (preprocessor)
406    {
407      cmd = xmalloc (strlen (preprocessor)
408		     + strlen (preprocargs)
409		     + strlen (filename)
410		     + 10);
411      sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
412
413      cpp_pipe = open_input_stream (cmd);
414    }
415  else
416    {
417      char *dash, *slash, *cp;
418
419      preprocessor = DEFAULT_PREPROCESSOR;
420
421      cmd = xmalloc (strlen (program_name)
422		     + strlen (preprocessor)
423		     + strlen (preprocargs)
424		     + strlen (filename)
425#ifdef HAVE_EXECUTABLE_SUFFIX
426		     + strlen (EXECUTABLE_SUFFIX)
427#endif
428		     + 10);
429
430
431      dash = slash = 0;
432      for (cp = program_name; *cp; cp++)
433	{
434	  if (*cp == '-')
435	    dash = cp;
436	  if (
437#if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
438	      *cp == ':' || *cp == '\\' ||
439#endif
440	      *cp == '/')
441	    {
442	      slash = cp;
443	      dash = 0;
444	    }
445	}
446
447      cpp_pipe = 0;
448
449      if (dash)
450	{
451	  /* First, try looking for a prefixed gcc in the windres
452	     directory, with the same prefix as windres */
453
454	  cpp_pipe = look_for_default (cmd, program_name, dash-program_name+1,
455				       preprocargs, filename);
456	}
457
458      if (slash && !cpp_pipe)
459	{
460	  /* Next, try looking for a gcc in the same directory as
461             that windres */
462
463	  cpp_pipe = look_for_default (cmd, program_name, slash-program_name+1,
464				       preprocargs, filename);
465	}
466
467      if (!cpp_pipe)
468	{
469	  /* Sigh, try the default */
470
471	  cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
472	}
473
474    }
475
476  free (cmd);
477
478  rc_filename = xstrdup (filename);
479  rc_lineno = 1;
480  if (language != -1)
481    rcparse_set_language (language);
482  yyin = cpp_pipe;
483  yyparse ();
484  rcparse_discard_strings ();
485
486  close_input_stream ();
487
488  if (fontdirs != NULL)
489    define_fontdirs ();
490
491  free (rc_filename);
492  rc_filename = NULL;
493
494  return resources;
495}
496
497/* Close the input stream if it is open.  */
498
499static void
500close_input_stream ()
501{
502  if (istream_type == ISTREAM_FILE)
503    {
504      if (cpp_pipe != NULL)
505	fclose (cpp_pipe);
506
507      if (cpp_temp_file != NULL)
508	{
509	  int errno_save = errno;
510
511	  unlink (cpp_temp_file);
512	  errno = errno_save;
513	  free (cpp_temp_file);
514	}
515    }
516  else
517    {
518      if (cpp_pipe != NULL)
519	pclose (cpp_pipe);
520    }
521
522  /* Since this is also run via xatexit, safeguard.  */
523  cpp_pipe = NULL;
524  cpp_temp_file = NULL;
525}
526
527/* Report an error while reading an rc file.  */
528
529void
530yyerror (msg)
531     const char *msg;
532{
533  fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
534}
535
536/* Issue a warning while reading an rc file.  */
537
538void
539rcparse_warning (msg)
540     const char *msg;
541{
542  fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
543}
544
545/* Die if we get an unexpected end of file.  */
546
547static void
548unexpected_eof (msg)
549     const char *msg;
550{
551  fatal (_("%s: unexpected EOF"), msg);
552}
553
554/* Read a 16 bit word from a file.  The data is assumed to be little
555   endian.  */
556
557static int
558get_word (e, msg)
559     FILE *e;
560     const char *msg;
561{
562  int b1, b2;
563
564  b1 = getc (e);
565  b2 = getc (e);
566  if (feof (e))
567    unexpected_eof (msg);
568  return ((b2 & 0xff) << 8) | (b1 & 0xff);
569}
570
571/* Read a 32 bit word from a file.  The data is assumed to be little
572   endian.  */
573
574static unsigned long
575get_long (e, msg)
576     FILE *e;
577     const char *msg;
578{
579  int b1, b2, b3, b4;
580
581  b1 = getc (e);
582  b2 = getc (e);
583  b3 = getc (e);
584  b4 = getc (e);
585  if (feof (e))
586    unexpected_eof (msg);
587  return (((((((b4 & 0xff) << 8)
588	      | (b3 & 0xff)) << 8)
589	    | (b2 & 0xff)) << 8)
590	  | (b1 & 0xff));
591}
592
593/* Read data from a file.  This is a wrapper to do error checking.  */
594
595static void
596get_data (e, p, c, msg)
597     FILE *e;
598     unsigned char *p;
599     unsigned long c;
600     const char *msg;
601{
602  unsigned long got;
603
604  got = fread (p, 1, c, e);
605  if (got == c)
606    return;
607
608  fatal (_("%s: read of %lu returned %lu"), msg, c, got);
609}
610
611/* Define an accelerator resource.  */
612
613void
614define_accelerator (id, resinfo, data)
615     struct res_id id;
616     const struct res_res_info *resinfo;
617     struct accelerator *data;
618{
619  struct res_resource *r;
620
621  r = define_standard_resource (&resources, RT_ACCELERATOR, id,
622				resinfo->language, 0);
623  r->type = RES_TYPE_ACCELERATOR;
624  r->u.acc = data;
625  r->res_info = *resinfo;
626}
627
628/* Define a bitmap resource.  Bitmap data is stored in a file.  The
629   first 14 bytes of the file are a standard header, which is not
630   included in the resource data.  */
631
632#define BITMAP_SKIP (14)
633
634void
635define_bitmap (id, resinfo, filename)
636     struct res_id id;
637     const struct res_res_info *resinfo;
638     const char *filename;
639{
640  FILE *e;
641  char *real_filename;
642  struct stat s;
643  unsigned char *data;
644  int i;
645  struct res_resource *r;
646
647  e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
648
649  if (stat (real_filename, &s) < 0)
650    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
651	   strerror (errno));
652
653  data = (unsigned char *) res_alloc (s.st_size - BITMAP_SKIP);
654
655  for (i = 0; i < BITMAP_SKIP; i++)
656    getc (e);
657
658  get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
659
660  fclose (e);
661  free (real_filename);
662
663  r = define_standard_resource (&resources, RT_BITMAP, id,
664				resinfo->language, 0);
665
666  r->type = RES_TYPE_BITMAP;
667  r->u.data.length = s.st_size - BITMAP_SKIP;
668  r->u.data.data = data;
669  r->res_info = *resinfo;
670}
671
672/* Define a cursor resource.  A cursor file may contain a set of
673   bitmaps, each representing the same cursor at various different
674   resolutions.  They each get written out with a different ID.  The
675   real cursor resource is then a group resource which can be used to
676   select one of the actual cursors.  */
677
678void
679define_cursor (id, resinfo, filename)
680     struct res_id id;
681     const struct res_res_info *resinfo;
682     const char *filename;
683{
684  FILE *e;
685  char *real_filename;
686  int type, count, i;
687  struct icondir *icondirs;
688  int first_cursor;
689  struct res_resource *r;
690  struct group_cursor *first, **pp;
691
692  e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
693
694  /* A cursor file is basically an icon file.  The start of the file
695     is a three word structure.  The first word is ignored.  The
696     second word is the type of data.  The third word is the number of
697     entries.  */
698
699  get_word (e, real_filename);
700  type = get_word (e, real_filename);
701  count = get_word (e, real_filename);
702  if (type != 2)
703    fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
704
705  /* Read in the icon directory entries.  */
706
707  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
708
709  for (i = 0; i < count; i++)
710    {
711      icondirs[i].width = getc (e);
712      icondirs[i].height = getc (e);
713      icondirs[i].colorcount = getc (e);
714      getc (e);
715      icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
716      icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
717      icondirs[i].bytes = get_long (e, real_filename);
718      icondirs[i].offset = get_long (e, real_filename);
719
720      if (feof (e))
721	unexpected_eof (real_filename);
722    }
723
724  /* Define each cursor as a unique resource.  */
725
726  first_cursor = cursors;
727
728  for (i = 0; i < count; i++)
729    {
730      unsigned char *data;
731      struct res_id name;
732      struct cursor *c;
733
734      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
735	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
736	       icondirs[i].offset, strerror (errno));
737
738      data = (unsigned char *) res_alloc (icondirs[i].bytes);
739
740      get_data (e, data, icondirs[i].bytes, real_filename);
741
742      c = (struct cursor *) res_alloc (sizeof *c);
743      c->xhotspot = icondirs[i].u.cursor.xhotspot;
744      c->yhotspot = icondirs[i].u.cursor.yhotspot;
745      c->length = icondirs[i].bytes;
746      c->data = data;
747
748      ++cursors;
749
750      name.named = 0;
751      name.u.id = cursors;
752
753      r = define_standard_resource (&resources, RT_CURSOR, name,
754				    resinfo->language, 0);
755      r->type = RES_TYPE_CURSOR;
756      r->u.cursor = c;
757      r->res_info = *resinfo;
758    }
759
760  fclose (e);
761  free (real_filename);
762
763  /* Define a cursor group resource.  */
764
765  first = NULL;
766  pp = &first;
767  for (i = 0; i < count; i++)
768    {
769      struct group_cursor *cg;
770
771      cg = (struct group_cursor *) res_alloc (sizeof *cg);
772      cg->next = NULL;
773      cg->width = icondirs[i].width;
774      cg->height = 2 * icondirs[i].height;
775
776      /* FIXME: What should these be set to?  */
777      cg->planes = 1;
778      cg->bits = 1;
779
780      cg->bytes = icondirs[i].bytes + 4;
781      cg->index = first_cursor + i + 1;
782
783      *pp = cg;
784      pp = &(*pp)->next;
785    }
786
787  free (icondirs);
788
789  r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
790				resinfo->language, 0);
791  r->type = RES_TYPE_GROUP_CURSOR;
792  r->u.group_cursor = first;
793  r->res_info = *resinfo;
794}
795
796/* Define a dialog resource.  */
797
798void
799define_dialog (id, resinfo, dialog)
800     struct res_id id;
801     const struct res_res_info *resinfo;
802     const struct dialog *dialog;
803{
804  struct dialog *copy;
805  struct res_resource *r;
806
807  copy = (struct dialog *) res_alloc (sizeof *copy);
808  *copy = *dialog;
809
810  r = define_standard_resource (&resources, RT_DIALOG, id,
811				resinfo->language, 0);
812  r->type = RES_TYPE_DIALOG;
813  r->u.dialog = copy;
814  r->res_info = *resinfo;
815}
816
817/* Define a dialog control.  This does not define a resource, but
818   merely allocates and fills in a structure.  */
819
820struct dialog_control *
821define_control (iid, id, x, y, width, height, class, style, exstyle)
822     struct res_id iid;
823     unsigned long id;
824     unsigned long x;
825     unsigned long y;
826     unsigned long width;
827     unsigned long height;
828     unsigned long class;
829     unsigned long style;
830     unsigned long exstyle;
831{
832  struct dialog_control *n;
833
834  n = (struct dialog_control *) res_alloc (sizeof *n);
835  n->next = NULL;
836  n->id = id;
837  n->style = style;
838  n->exstyle = exstyle;
839  n->x = x;
840  n->y = y;
841  n->width = width;
842  n->height = height;
843  n->class.named = 0;
844  n->class.u.id = class;
845  n->text = iid;
846  n->data = NULL;
847  n->help = 0;
848
849  return n;
850}
851
852struct dialog_control *
853define_icon_control (iid, id, x, y, style, exstyle, help, data, ex)
854     struct res_id iid;
855     unsigned long id;
856     unsigned long x;
857     unsigned long y;
858     unsigned long style;
859     unsigned long exstyle;
860     unsigned long help;
861     struct rcdata_item *data;
862     struct dialog_ex *ex;
863{
864  struct dialog_control *n;
865  struct res_id tid;
866
867  if (style == 0)
868    style = SS_ICON | WS_CHILD | WS_VISIBLE;
869  res_string_to_id (&tid, "");
870  n = define_control (tid, id, x, y, 0, 0, CTL_STATIC, style, exstyle);
871  n->text = iid;
872  if (help && !ex)
873    rcparse_warning (_("help ID requires DIALOGEX"));
874  if (data && !ex)
875    rcparse_warning (_("control data requires DIALOGEX"));
876  n->help = help;
877  n->data = data;
878
879  return n;
880}
881
882/* Define a font resource.  */
883
884void
885define_font (id, resinfo, filename)
886     struct res_id id;
887     const struct res_res_info *resinfo;
888     const char *filename;
889{
890  FILE *e;
891  char *real_filename;
892  struct stat s;
893  unsigned char *data;
894  struct res_resource *r;
895  long offset;
896  long fontdatalength;
897  unsigned char *fontdata;
898  struct fontdir *fd;
899  const char *device, *face;
900  struct fontdir **pp;
901
902  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
903
904  if (stat (real_filename, &s) < 0)
905    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
906	   strerror (errno));
907
908  data = (unsigned char *) res_alloc (s.st_size);
909
910  get_data (e, data, s.st_size, real_filename);
911
912  fclose (e);
913  free (real_filename);
914
915  r = define_standard_resource (&resources, RT_FONT, id,
916				resinfo->language, 0);
917
918  r->type = RES_TYPE_FONT;
919  r->u.data.length = s.st_size;
920  r->u.data.data = data;
921  r->res_info = *resinfo;
922
923  /* For each font resource, we must add an entry in the FONTDIR
924     resource.  The FONTDIR resource includes some strings in the font
925     file.  To find them, we have to do some magic on the data we have
926     read.  */
927
928  offset = ((((((data[47] << 8)
929		| data[46]) << 8)
930	      | data[45]) << 8)
931	    | data[44]);
932  if (offset > 0 && offset < s.st_size)
933    device = (char *) data + offset;
934  else
935    device = "";
936
937  offset = ((((((data[51] << 8)
938		| data[50]) << 8)
939	      | data[49]) << 8)
940	    | data[48]);
941  if (offset > 0 && offset < s.st_size)
942    face = (char *) data + offset;
943  else
944    face = "";
945
946  ++fonts;
947
948  fontdatalength = 58 + strlen (device) + strlen (face);
949  fontdata = (unsigned char *) res_alloc (fontdatalength);
950  memcpy (fontdata, data, 56);
951  strcpy ((char *) fontdata + 56, device);
952  strcpy ((char *) fontdata + 57 + strlen (device), face);
953
954  fd = (struct fontdir *) res_alloc (sizeof *fd);
955  fd->next = NULL;
956  fd->index = fonts;
957  fd->length = fontdatalength;
958  fd->data = fontdata;
959
960  for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
961    ;
962  *pp = fd;
963
964  /* For the single fontdirs resource, we always use the resource
965     information of the last font.  I don't know what else to do.  */
966  fontdirs_resinfo = *resinfo;
967}
968
969/* Define the fontdirs resource.  This is called after the entire rc
970   file has been parsed, if any font resources were seen.  */
971
972static void
973define_fontdirs ()
974{
975  struct res_resource *r;
976  struct res_id id;
977
978  id.named = 0;
979  id.u.id = 1;
980
981  r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
982
983  r->type = RES_TYPE_FONTDIR;
984  r->u.fontdir = fontdirs;
985  r->res_info = fontdirs_resinfo;
986}
987
988/* Define an icon resource.  An icon file may contain a set of
989   bitmaps, each representing the same icon at various different
990   resolutions.  They each get written out with a different ID.  The
991   real icon resource is then a group resource which can be used to
992   select one of the actual icon bitmaps.  */
993
994void
995define_icon (id, resinfo, filename)
996     struct res_id id;
997     const struct res_res_info *resinfo;
998     const char *filename;
999{
1000  FILE *e;
1001  char *real_filename;
1002  int type, count, i;
1003  struct icondir *icondirs;
1004  int first_icon;
1005  struct res_resource *r;
1006  struct group_icon *first, **pp;
1007
1008  e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
1009
1010  /* The start of an icon file is a three word structure.  The first
1011     word is ignored.  The second word is the type of data.  The third
1012     word is the number of entries.  */
1013
1014  get_word (e, real_filename);
1015  type = get_word (e, real_filename);
1016  count = get_word (e, real_filename);
1017  if (type != 1)
1018    fatal (_("icon file `%s' does not contain icon data"), real_filename);
1019
1020  /* Read in the icon directory entries.  */
1021
1022  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
1023
1024  for (i = 0; i < count; i++)
1025    {
1026      icondirs[i].width = getc (e);
1027      icondirs[i].height = getc (e);
1028      icondirs[i].colorcount = getc (e);
1029      getc (e);
1030      icondirs[i].u.icon.planes = get_word (e, real_filename);
1031      icondirs[i].u.icon.bits = get_word (e, real_filename);
1032      icondirs[i].bytes = get_long (e, real_filename);
1033      icondirs[i].offset = get_long (e, real_filename);
1034
1035      if (feof (e))
1036	unexpected_eof (real_filename);
1037    }
1038
1039  /* Define each icon as a unique resource.  */
1040
1041  first_icon = icons;
1042
1043  for (i = 0; i < count; i++)
1044    {
1045      unsigned char *data;
1046      struct res_id name;
1047
1048      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
1049	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
1050	       icondirs[i].offset, strerror (errno));
1051
1052      data = (unsigned char *) res_alloc (icondirs[i].bytes);
1053
1054      get_data (e, data, icondirs[i].bytes, real_filename);
1055
1056      ++icons;
1057
1058      name.named = 0;
1059      name.u.id = icons;
1060
1061      r = define_standard_resource (&resources, RT_ICON, name,
1062				    resinfo->language, 0);
1063      r->type = RES_TYPE_ICON;
1064      r->u.data.length = icondirs[i].bytes;
1065      r->u.data.data = data;
1066      r->res_info = *resinfo;
1067    }
1068
1069  fclose (e);
1070  free (real_filename);
1071
1072  /* Define an icon group resource.  */
1073
1074  first = NULL;
1075  pp = &first;
1076  for (i = 0; i < count; i++)
1077    {
1078      struct group_icon *cg;
1079
1080      /* For some reason, at least in some files the planes and bits
1081         are zero.  We instead set them from the color.  This is
1082         copied from rcl.  */
1083
1084      cg = (struct group_icon *) res_alloc (sizeof *cg);
1085      cg->next = NULL;
1086      cg->width = icondirs[i].width;
1087      cg->height = icondirs[i].height;
1088      cg->colors = icondirs[i].colorcount;
1089
1090      cg->planes = 1;
1091      cg->bits = 0;
1092      while ((1 << cg->bits) < cg->colors)
1093	++cg->bits;
1094
1095      cg->bytes = icondirs[i].bytes;
1096      cg->index = first_icon + i + 1;
1097
1098      *pp = cg;
1099      pp = &(*pp)->next;
1100    }
1101
1102  free (icondirs);
1103
1104  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1105				resinfo->language, 0);
1106  r->type = RES_TYPE_GROUP_ICON;
1107  r->u.group_icon = first;
1108  r->res_info = *resinfo;
1109}
1110
1111/* Define a menu resource.  */
1112
1113void
1114define_menu (id, resinfo, menuitems)
1115     struct res_id id;
1116     const struct res_res_info *resinfo;
1117     struct menuitem *menuitems;
1118{
1119  struct menu *m;
1120  struct res_resource *r;
1121
1122  m = (struct menu *) res_alloc (sizeof *m);
1123  m->items = menuitems;
1124  m->help = 0;
1125
1126  r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1127  r->type = RES_TYPE_MENU;
1128  r->u.menu = m;
1129  r->res_info = *resinfo;
1130}
1131
1132/* Define a menu item.  This does not define a resource, but merely
1133   allocates and fills in a structure.  */
1134
1135struct menuitem *
1136define_menuitem (text, menuid, type, state, help, menuitems)
1137     const char *text;
1138     int menuid;
1139     unsigned long type;
1140     unsigned long state;
1141     unsigned long help;
1142     struct menuitem *menuitems;
1143{
1144  struct menuitem *mi;
1145
1146  mi = (struct menuitem *) res_alloc (sizeof *mi);
1147  mi->next = NULL;
1148  mi->type = type;
1149  mi->state = state;
1150  mi->id = menuid;
1151  if (text == NULL)
1152    mi->text = NULL;
1153  else
1154    unicode_from_ascii ((int *) NULL, &mi->text, text);
1155  mi->help = help;
1156  mi->popup = menuitems;
1157  return mi;
1158}
1159
1160/* Define a messagetable resource.  */
1161
1162void
1163define_messagetable (id, resinfo, filename)
1164     struct res_id id;
1165     const struct res_res_info *resinfo;
1166     const char *filename;
1167{
1168  FILE *e;
1169  char *real_filename;
1170  struct stat s;
1171  unsigned char *data;
1172  struct res_resource *r;
1173
1174  e = open_file_search (filename, FOPEN_RB, "messagetable file",
1175			&real_filename);
1176
1177  if (stat (real_filename, &s) < 0)
1178    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1179	   strerror (errno));
1180
1181  data = (unsigned char *) res_alloc (s.st_size);
1182
1183  get_data (e, data, s.st_size, real_filename);
1184
1185  fclose (e);
1186  free (real_filename);
1187
1188  r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1189				resinfo->language, 0);
1190
1191  r->type = RES_TYPE_MESSAGETABLE;
1192  r->u.data.length = s.st_size;
1193  r->u.data.data = data;
1194  r->res_info = *resinfo;
1195}
1196
1197/* Define an rcdata resource.  */
1198
1199void
1200define_rcdata (id, resinfo, data)
1201     struct res_id id;
1202     const struct res_res_info *resinfo;
1203     struct rcdata_item *data;
1204{
1205  struct res_resource *r;
1206
1207  r = define_standard_resource (&resources, RT_RCDATA, id,
1208				resinfo->language, 0);
1209  r->type = RES_TYPE_RCDATA;
1210  r->u.rcdata = data;
1211  r->res_info = *resinfo;
1212}
1213
1214/* Create an rcdata item holding a string.  */
1215
1216struct rcdata_item *
1217define_rcdata_string (string, len)
1218     const char *string;
1219     unsigned long len;
1220{
1221  struct rcdata_item *ri;
1222  char *s;
1223
1224  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
1225  ri->next = NULL;
1226  ri->type = RCDATA_STRING;
1227  ri->u.string.length = len;
1228  s = (char *) res_alloc (len);
1229  memcpy (s, string, len);
1230  ri->u.string.s = s;
1231
1232  return ri;
1233}
1234
1235/* Create an rcdata item holding a number.  */
1236
1237struct rcdata_item *
1238define_rcdata_number (val, dword)
1239     unsigned long val;
1240     int dword;
1241{
1242  struct rcdata_item *ri;
1243
1244  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
1245  ri->next = NULL;
1246  ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1247  ri->u.word = val;
1248
1249  return ri;
1250}
1251
1252/* Define a stringtable resource.  This is called for each string
1253   which appears in a STRINGTABLE statement.  */
1254
1255void
1256define_stringtable (resinfo, stringid, string)
1257     const struct res_res_info *resinfo;
1258     unsigned long stringid;
1259     const char *string;
1260{
1261  struct res_id id;
1262  struct res_resource *r;
1263
1264  id.named = 0;
1265  id.u.id = (stringid >> 4) + 1;
1266  r = define_standard_resource (&resources, RT_STRING, id,
1267				resinfo->language, 1);
1268
1269  if (r->type == RES_TYPE_UNINITIALIZED)
1270    {
1271      int i;
1272
1273      r->type = RES_TYPE_STRINGTABLE;
1274      r->u.stringtable = ((struct stringtable *)
1275			  res_alloc (sizeof (struct stringtable)));
1276      for (i = 0; i < 16; i++)
1277	{
1278	  r->u.stringtable->strings[i].length = 0;
1279	  r->u.stringtable->strings[i].string = NULL;
1280	}
1281
1282      r->res_info = *resinfo;
1283    }
1284
1285  unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
1286		      &r->u.stringtable->strings[stringid & 0xf].string,
1287		      string);
1288}
1289
1290/* Define a user data resource where the data is in the rc file.  */
1291
1292void
1293define_user_data (id, type, resinfo, data)
1294     struct res_id id;
1295     struct res_id type;
1296     const struct res_res_info *resinfo;
1297     struct rcdata_item *data;
1298{
1299  struct res_id ids[3];
1300  struct res_resource *r;
1301
1302  ids[0] = type;
1303  ids[1] = id;
1304  ids[2].named = 0;
1305  ids[2].u.id = resinfo->language;
1306
1307  r = define_resource (&resources, 3, ids, 0);
1308  r->type = RES_TYPE_USERDATA;
1309  r->u.userdata = data;
1310  r->res_info = *resinfo;
1311}
1312
1313/* Define a user data resource where the data is in a file.  */
1314
1315void
1316define_user_file (id, type, resinfo, filename)
1317     struct res_id id;
1318     struct res_id type;
1319     const struct res_res_info *resinfo;
1320     const char *filename;
1321{
1322  FILE *e;
1323  char *real_filename;
1324  struct stat s;
1325  unsigned char *data;
1326  struct res_id ids[3];
1327  struct res_resource *r;
1328
1329  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
1330
1331  if (stat (real_filename, &s) < 0)
1332    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1333	   strerror (errno));
1334
1335  data = (unsigned char *) res_alloc (s.st_size);
1336
1337  get_data (e, data, s.st_size, real_filename);
1338
1339  fclose (e);
1340  free (real_filename);
1341
1342  ids[0] = type;
1343  ids[1] = id;
1344  ids[2].named = 0;
1345  ids[2].u.id = resinfo->language;
1346
1347  r = define_resource (&resources, 3, ids, 0);
1348  r->type = RES_TYPE_USERDATA;
1349  r->u.userdata = ((struct rcdata_item *)
1350		   res_alloc (sizeof (struct rcdata_item)));
1351  r->u.userdata->next = NULL;
1352  r->u.userdata->type = RCDATA_BUFFER;
1353  r->u.userdata->u.buffer.length = s.st_size;
1354  r->u.userdata->u.buffer.data = data;
1355  r->res_info = *resinfo;
1356}
1357
1358/* Define a versioninfo resource.  */
1359
1360void
1361define_versioninfo (id, language, fixedverinfo, verinfo)
1362     struct res_id id;
1363     int language;
1364     struct fixed_versioninfo *fixedverinfo;
1365     struct ver_info *verinfo;
1366{
1367  struct res_resource *r;
1368
1369  r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1370  r->type = RES_TYPE_VERSIONINFO;
1371  r->u.versioninfo = ((struct versioninfo *)
1372		      res_alloc (sizeof (struct versioninfo)));
1373  r->u.versioninfo->fixed = fixedverinfo;
1374  r->u.versioninfo->var = verinfo;
1375  r->res_info.language = language;
1376}
1377
1378/* Add string version info to a list of version information.  */
1379
1380struct ver_info *
1381append_ver_stringfileinfo (verinfo, language, strings)
1382     struct ver_info *verinfo;
1383     const char *language;
1384     struct ver_stringinfo *strings;
1385{
1386  struct ver_info *vi, **pp;
1387
1388  vi = (struct ver_info *) res_alloc (sizeof *vi);
1389  vi->next = NULL;
1390  vi->type = VERINFO_STRING;
1391  unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
1392  vi->u.string.strings = strings;
1393
1394  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1395    ;
1396  *pp = vi;
1397
1398  return verinfo;
1399}
1400
1401/* Add variable version info to a list of version information.  */
1402
1403struct ver_info *
1404append_ver_varfileinfo (verinfo, key, var)
1405     struct ver_info *verinfo;
1406     const char *key;
1407     struct ver_varinfo *var;
1408{
1409  struct ver_info *vi, **pp;
1410
1411  vi = (struct ver_info *) res_alloc (sizeof *vi);
1412  vi->next = NULL;
1413  vi->type = VERINFO_VAR;
1414  unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
1415  vi->u.var.var = var;
1416
1417  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1418    ;
1419  *pp = vi;
1420
1421  return verinfo;
1422}
1423
1424/* Append version string information to a list.  */
1425
1426struct ver_stringinfo *
1427append_verval (strings, key, value)
1428     struct ver_stringinfo *strings;
1429     const char *key;
1430     const char *value;
1431{
1432  struct ver_stringinfo *vs, **pp;
1433
1434  vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
1435  vs->next = NULL;
1436  unicode_from_ascii ((int *) NULL, &vs->key, key);
1437  unicode_from_ascii ((int *) NULL, &vs->value, value);
1438
1439  for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1440    ;
1441  *pp = vs;
1442
1443  return strings;
1444}
1445
1446/* Append version variable information to a list.  */
1447
1448struct ver_varinfo *
1449append_vertrans (var, language, charset)
1450     struct ver_varinfo *var;
1451     unsigned long language;
1452     unsigned long charset;
1453{
1454  struct ver_varinfo *vv, **pp;
1455
1456  vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
1457  vv->next = NULL;
1458  vv->language = language;
1459  vv->charset = charset;
1460
1461  for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1462    ;
1463  *pp = vv;
1464
1465  return var;
1466}
1467
1468/* Local functions used to write out an rc file.  */
1469
1470static void indent PARAMS ((FILE *, int));
1471static void write_rc_directory
1472  PARAMS ((FILE *, const struct res_directory *, const struct res_id *,
1473	   const struct res_id *, int *, int));
1474static void write_rc_subdir
1475  PARAMS ((FILE *, const struct res_entry *, const struct res_id *,
1476	   const struct res_id *, int *, int));
1477static void write_rc_resource
1478  PARAMS ((FILE *, const struct res_id *, const struct res_id *,
1479	   const struct res_resource *, int *));
1480static void write_rc_accelerators
1481  PARAMS ((FILE *, const struct accelerator *));
1482static void write_rc_cursor PARAMS ((FILE *, const struct cursor *));
1483static void write_rc_group_cursor
1484  PARAMS ((FILE *, const struct group_cursor *));
1485static void write_rc_dialog PARAMS ((FILE *, const struct dialog *));
1486static void write_rc_dialog_control
1487  PARAMS ((FILE *, const struct dialog_control *));
1488static void write_rc_fontdir PARAMS ((FILE *, const struct fontdir *));
1489static void write_rc_group_icon PARAMS ((FILE *, const struct group_icon *));
1490static void write_rc_menu PARAMS ((FILE *, const struct menu *, int));
1491static void write_rc_menuitems
1492  PARAMS ((FILE *, const struct menuitem *, int, int));
1493static void write_rc_rcdata PARAMS ((FILE *, const struct rcdata_item *, int));
1494static void write_rc_stringtable
1495  PARAMS ((FILE *, const struct res_id *, const struct stringtable *));
1496static void write_rc_versioninfo PARAMS ((FILE *, const struct versioninfo *));
1497static void write_rc_filedata
1498  PARAMS ((FILE *, unsigned long, const unsigned char *));
1499
1500/* Indent a given number of spaces.  */
1501
1502static void
1503indent (e, c)
1504     FILE *e;
1505     int c;
1506{
1507  int i;
1508
1509  for (i = 0; i < c; i++)
1510    putc (' ', e);
1511}
1512
1513/* Dump the resources we have read in the format of an rc file.
1514
1515   Actually, we don't use the format of an rc file, because it's way
1516   too much of a pain--for example, we'd have to write icon resources
1517   into a file and refer to that file.  We just generate a readable
1518   format that kind of looks like an rc file, and is useful for
1519   understanding the contents of a resource file.  Someday we may want
1520   to generate an rc file which the rc compiler can read; if that day
1521   comes, this code will have to be fixed up.  */
1522
1523void
1524write_rc_file (filename, resources)
1525     const char *filename;
1526     const struct res_directory *resources;
1527{
1528  FILE *e;
1529  int language;
1530
1531  if (filename == NULL)
1532    e = stdout;
1533  else
1534    {
1535      e = fopen (filename, FOPEN_WT);
1536      if (e == NULL)
1537	fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1538    }
1539
1540  language = -1;
1541  write_rc_directory (e, resources, (const struct res_id *) NULL,
1542		      (const struct res_id *) NULL, &language, 1);
1543}
1544
1545/* Write out a directory.  E is the file to write to.  RD is the
1546   directory.  TYPE is a pointer to the level 1 ID which serves as the
1547   resource type.  NAME is a pointer to the level 2 ID which serves as
1548   an individual resource name.  LANGUAGE is a pointer to the current
1549   language.  LEVEL is the level in the tree.  */
1550
1551static void
1552write_rc_directory (e, rd, type, name, language, level)
1553     FILE *e;
1554     const struct res_directory *rd;
1555     const struct res_id *type;
1556     const struct res_id *name;
1557     int *language;
1558     int level;
1559{
1560  const struct res_entry *re;
1561
1562  /* Print out some COFF information that rc files can't represent.  */
1563
1564  if (rd->time != 0)
1565    fprintf (e, "// Time stamp: %lu\n", rd->time);
1566  if (rd->characteristics != 0)
1567    fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
1568  if (rd->major != 0 || rd->minor != 0)
1569    fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
1570
1571  for (re = rd->entries;  re != NULL; re = re->next)
1572    {
1573      switch (level)
1574	{
1575	case 1:
1576	  /* If we're at level 1, the key of this resource is the
1577             type.  This normally duplicates the information we have
1578             stored with the resource itself, but we need to remember
1579             the type if this is a user define resource type.  */
1580	  type = &re->id;
1581	  break;
1582
1583	case 2:
1584	  /* If we're at level 2, the key of this resource is the name
1585	     we are going to use in the rc printout.  */
1586	  name = &re->id;
1587	  break;
1588
1589	case 3:
1590	  /* If we're at level 3, then this key represents a language.
1591	     Use it to update the current language.  */
1592	  if (! re->id.named
1593	      && re->id.u.id != (unsigned long) (unsigned int) *language
1594	      && (re->id.u.id & 0xffff) == re->id.u.id)
1595	    {
1596	      fprintf (e, "LANGUAGE %lu, %lu\n",
1597		       re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
1598		       (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
1599	      *language = re->id.u.id;
1600	    }
1601	  break;
1602
1603	default:
1604	  break;
1605	}
1606
1607      if (re->subdir)
1608	write_rc_subdir (e, re, type, name, language, level);
1609      else
1610	{
1611	  if (level == 3)
1612	    {
1613	      /* This is the normal case: the three levels are
1614                 TYPE/NAME/LANGUAGE.  NAME will have been set at level
1615                 2, and represents the name to use.  We probably just
1616                 set LANGUAGE, and it will probably match what the
1617                 resource itself records if anything.  */
1618	      write_rc_resource (e, type, name, re->u.res, language);
1619	    }
1620	  else
1621	    {
1622	      fprintf (e, "// Resource at unexpected level %d\n", level);
1623	      write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
1624				 language);
1625	    }
1626	}
1627    }
1628}
1629
1630/* Write out a subdirectory entry.  E is the file to write to.  RE is
1631   the subdirectory entry.  TYPE and NAME are pointers to higher level
1632   IDs, or NULL.  LANGUAGE is a pointer to the current language.
1633   LEVEL is the level in the tree.  */
1634
1635static void
1636write_rc_subdir (e, re, type, name, language, level)
1637     FILE *e;
1638     const struct res_entry *re;
1639     const struct res_id *type;
1640     const struct res_id *name;
1641     int *language;
1642     int level;
1643{
1644  fprintf (e, "\n");
1645  switch (level)
1646    {
1647    case 1:
1648      fprintf (e, "// Type: ");
1649      if (re->id.named)
1650	res_id_print (e, re->id, 1);
1651      else
1652	{
1653	  const char *s;
1654
1655	  switch (re->id.u.id)
1656	    {
1657	    case RT_CURSOR: s = "cursor"; break;
1658	    case RT_BITMAP: s = "bitmap"; break;
1659	    case RT_ICON: s = "icon"; break;
1660	    case RT_MENU: s = "menu"; break;
1661	    case RT_DIALOG: s = "dialog"; break;
1662	    case RT_STRING: s = "stringtable"; break;
1663	    case RT_FONTDIR: s = "fontdir"; break;
1664	    case RT_FONT: s = "font"; break;
1665	    case RT_ACCELERATOR: s = "accelerators"; break;
1666	    case RT_RCDATA: s = "rcdata"; break;
1667	    case RT_MESSAGETABLE: s = "messagetable"; break;
1668	    case RT_GROUP_CURSOR: s = "group cursor"; break;
1669	    case RT_GROUP_ICON: s = "group icon"; break;
1670	    case RT_VERSION: s = "version"; break;
1671	    case RT_DLGINCLUDE: s = "dlginclude"; break;
1672	    case RT_PLUGPLAY: s = "plugplay"; break;
1673	    case RT_VXD: s = "vxd"; break;
1674	    case RT_ANICURSOR: s = "anicursor"; break;
1675	    case RT_ANIICON: s = "aniicon"; break;
1676	    default: s = NULL; break;
1677	    }
1678
1679	  if (s != NULL)
1680	    fprintf (e, "%s", s);
1681	  else
1682	    res_id_print (e, re->id, 1);
1683	}
1684      fprintf (e, "\n");
1685      break;
1686
1687    case 2:
1688      fprintf (e, "// Name: ");
1689      res_id_print (e, re->id, 1);
1690      fprintf (e, "\n");
1691      break;
1692
1693    case 3:
1694      fprintf (e, "// Language: ");
1695      res_id_print (e, re->id, 1);
1696      fprintf (e, "\n");
1697      break;
1698
1699    default:
1700      fprintf (e, "// Level %d: ", level);
1701      res_id_print (e, re->id, 1);
1702      fprintf (e, "\n");
1703    }
1704
1705  write_rc_directory (e, re->u.dir, type, name, language, level + 1);
1706}
1707
1708/* Write out a single resource.  E is the file to write to.  TYPE is a
1709   pointer to the type of the resource.  NAME is a pointer to the name
1710   of the resource; it will be NULL if there is a level mismatch.  RES
1711   is the resource data.  LANGUAGE is a pointer to the current
1712   language.  */
1713
1714static void
1715write_rc_resource (e, type, name, res, language)
1716     FILE *e;
1717     const struct res_id *type;
1718     const struct res_id *name;
1719     const struct res_resource *res;
1720     int *language;
1721{
1722  const char *s;
1723  int rt;
1724  int menuex = 0;
1725
1726  fprintf (e, "\n");
1727
1728  switch (res->type)
1729    {
1730    default:
1731      abort ();
1732
1733    case RES_TYPE_ACCELERATOR:
1734      s = "ACCELERATOR";
1735      rt = RT_ACCELERATOR;
1736      break;
1737
1738    case RES_TYPE_BITMAP:
1739      s = "BITMAP";
1740      rt = RT_BITMAP;
1741      break;
1742
1743    case RES_TYPE_CURSOR:
1744      s = "CURSOR";
1745      rt = RT_CURSOR;
1746      break;
1747
1748    case RES_TYPE_GROUP_CURSOR:
1749      s = "GROUP_CURSOR";
1750      rt = RT_GROUP_CURSOR;
1751      break;
1752
1753    case RES_TYPE_DIALOG:
1754      if (extended_dialog (res->u.dialog))
1755	s = "DIALOGEX";
1756      else
1757	s = "DIALOG";
1758      rt = RT_DIALOG;
1759      break;
1760
1761    case RES_TYPE_FONT:
1762      s = "FONT";
1763      rt = RT_FONT;
1764      break;
1765
1766    case RES_TYPE_FONTDIR:
1767      s = "FONTDIR";
1768      rt = RT_FONTDIR;
1769      break;
1770
1771    case RES_TYPE_ICON:
1772      s = "ICON";
1773      rt = RT_ICON;
1774      break;
1775
1776    case RES_TYPE_GROUP_ICON:
1777      s = "GROUP_ICON";
1778      rt = RT_GROUP_ICON;
1779      break;
1780
1781    case RES_TYPE_MENU:
1782      if (extended_menu (res->u.menu))
1783	{
1784	  s = "MENUEX";
1785	  menuex = 1;
1786	}
1787      else
1788	{
1789	  s = "MENU";
1790	  menuex = 0;
1791	}
1792      rt = RT_MENU;
1793      break;
1794
1795    case RES_TYPE_MESSAGETABLE:
1796      s = "MESSAGETABLE";
1797      rt = RT_MESSAGETABLE;
1798      break;
1799
1800    case RES_TYPE_RCDATA:
1801      s = "RCDATA";
1802      rt = RT_RCDATA;
1803      break;
1804
1805    case RES_TYPE_STRINGTABLE:
1806      s = "STRINGTABLE";
1807      rt = RT_STRING;
1808      break;
1809
1810    case RES_TYPE_USERDATA:
1811      s = NULL;
1812      rt = 0;
1813      break;
1814
1815    case RES_TYPE_VERSIONINFO:
1816      s = "VERSIONINFO";
1817      rt = RT_VERSION;
1818      break;
1819    }
1820
1821  if (rt != 0
1822      && type != NULL
1823      && (type->named || type->u.id != (unsigned long) rt))
1824    {
1825      fprintf (e, "// Unexpected resource type mismatch: ");
1826      res_id_print (e, *type, 1);
1827      fprintf (e, " != %d", rt);
1828    }
1829
1830  if (res->coff_info.codepage != 0)
1831    fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
1832  if (res->coff_info.reserved != 0)
1833    fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
1834
1835  if (name != NULL)
1836    res_id_print (e, *name, 0);
1837  else
1838    fprintf (e, "??Unknown-Name??");
1839
1840  fprintf (e, " ");
1841  if (s != NULL)
1842    fprintf (e, "%s", s);
1843  else if (type != NULL)
1844    res_id_print (e, *type, 0);
1845  else
1846    fprintf (e, "??Unknown-Type??");
1847
1848  if (res->res_info.memflags != 0)
1849    {
1850      if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
1851	fprintf (e, " MOVEABLE");
1852      if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
1853	fprintf (e, " PURE");
1854      if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
1855	fprintf (e, " PRELOAD");
1856      if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
1857	fprintf (e, " DISCARDABLE");
1858    }
1859
1860  if (res->type == RES_TYPE_DIALOG)
1861    {
1862      fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
1863	       res->u.dialog->width, res->u.dialog->height);
1864      if (res->u.dialog->ex != NULL
1865	  && res->u.dialog->ex->help != 0)
1866	fprintf (e, ", %lu", res->u.dialog->ex->help);
1867    }
1868
1869  fprintf (e, "\n");
1870
1871  if ((res->res_info.language != 0 && res->res_info.language != *language)
1872      || res->res_info.characteristics != 0
1873      || res->res_info.version != 0)
1874    {
1875      int modifiers;
1876
1877      switch (res->type)
1878	{
1879	case RES_TYPE_ACCELERATOR:
1880	case RES_TYPE_DIALOG:
1881	case RES_TYPE_MENU:
1882	case RES_TYPE_RCDATA:
1883	case RES_TYPE_STRINGTABLE:
1884	  modifiers = 1;
1885	  break;
1886
1887	default:
1888	  modifiers = 0;
1889	  break;
1890	}
1891
1892      if (res->res_info.language != 0 && res->res_info.language != *language)
1893	fprintf (e, "%sLANGUAGE %d, %d\n",
1894		 modifiers ? "// " : "",
1895		 res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
1896		 (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
1897      if (res->res_info.characteristics != 0)
1898	fprintf (e, "%sCHARACTERISTICS %lu\n",
1899		 modifiers ? "// " : "",
1900		 res->res_info.characteristics);
1901      if (res->res_info.version != 0)
1902	fprintf (e, "%sVERSION %lu\n",
1903		 modifiers ? "// " : "",
1904		 res->res_info.version);
1905    }
1906
1907  switch (res->type)
1908    {
1909    default:
1910      abort ();
1911
1912    case RES_TYPE_ACCELERATOR:
1913      write_rc_accelerators (e, res->u.acc);
1914      break;
1915
1916    case RES_TYPE_CURSOR:
1917      write_rc_cursor (e, res->u.cursor);
1918      break;
1919
1920    case RES_TYPE_GROUP_CURSOR:
1921      write_rc_group_cursor (e, res->u.group_cursor);
1922      break;
1923
1924    case RES_TYPE_DIALOG:
1925      write_rc_dialog (e, res->u.dialog);
1926      break;
1927
1928    case RES_TYPE_FONTDIR:
1929      write_rc_fontdir (e, res->u.fontdir);
1930      break;
1931
1932    case RES_TYPE_GROUP_ICON:
1933      write_rc_group_icon (e, res->u.group_icon);
1934      break;
1935
1936    case RES_TYPE_MENU:
1937      write_rc_menu (e, res->u.menu, menuex);
1938      break;
1939
1940    case RES_TYPE_RCDATA:
1941      write_rc_rcdata (e, res->u.rcdata, 0);
1942      break;
1943
1944    case RES_TYPE_STRINGTABLE:
1945      write_rc_stringtable (e, name, res->u.stringtable);
1946      break;
1947
1948    case RES_TYPE_USERDATA:
1949      write_rc_rcdata (e, res->u.userdata, 0);
1950      break;
1951
1952    case RES_TYPE_VERSIONINFO:
1953      write_rc_versioninfo (e, res->u.versioninfo);
1954      break;
1955
1956    case RES_TYPE_BITMAP:
1957    case RES_TYPE_FONT:
1958    case RES_TYPE_ICON:
1959    case RES_TYPE_MESSAGETABLE:
1960      write_rc_filedata (e, res->u.data.length, res->u.data.data);
1961      break;
1962    }
1963}
1964
1965/* Write out accelerator information.  */
1966
1967static void
1968write_rc_accelerators (e, accelerators)
1969     FILE *e;
1970     const struct accelerator *accelerators;
1971{
1972  const struct accelerator *acc;
1973
1974  fprintf (e, "BEGIN\n");
1975  for (acc = accelerators; acc != NULL; acc = acc->next)
1976    {
1977      int printable;
1978
1979      fprintf (e, "  ");
1980
1981      if ((acc->key & 0x7f) == acc->key
1982	  && ISPRINT (acc->key)
1983	  && (acc->flags & ACC_VIRTKEY) == 0)
1984	{
1985	  fprintf (e, "\"%c\"", acc->key);
1986	  printable = 1;
1987	}
1988      else
1989	{
1990	  fprintf (e, "%d", acc->key);
1991	  printable = 0;
1992	}
1993
1994      fprintf (e, ", %d", acc->id);
1995
1996      if (! printable)
1997	{
1998	  if ((acc->flags & ACC_VIRTKEY) != 0)
1999	    fprintf (e, ", VIRTKEY");
2000	  else
2001	    fprintf (e, ", ASCII");
2002	}
2003
2004      if ((acc->flags & ACC_SHIFT) != 0)
2005	fprintf (e, ", SHIFT");
2006      if ((acc->flags & ACC_CONTROL) != 0)
2007	fprintf (e, ", CONTROL");
2008      if ((acc->flags & ACC_ALT) != 0)
2009	fprintf (e, ", ALT");
2010
2011      fprintf (e, "\n");
2012    }
2013
2014  fprintf (e, "END\n");
2015}
2016
2017/* Write out cursor information.  This would normally be in a separate
2018   file, which the rc file would include.  */
2019
2020static void
2021write_rc_cursor (e, cursor)
2022     FILE *e;
2023     const struct cursor *cursor;
2024{
2025  fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
2026	   cursor->yhotspot);
2027  write_rc_filedata (e, cursor->length, cursor->data);
2028}
2029
2030/* Write out group cursor data.  This would normally be built from the
2031   cursor data.  */
2032
2033static void
2034write_rc_group_cursor (e, group_cursor)
2035     FILE *e;
2036     const struct group_cursor *group_cursor;
2037{
2038  const struct group_cursor *gc;
2039
2040  for (gc = group_cursor; gc != NULL; gc = gc->next)
2041    {
2042      fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
2043	     gc->width, gc->height, gc->planes, gc->bits);
2044      fprintf (e, "// data bytes: %lu; index: %d\n",
2045	       gc->bytes, gc->index);
2046    }
2047}
2048
2049/* Write dialog data.  */
2050
2051static void
2052write_rc_dialog (e, dialog)
2053     FILE *e;
2054     const struct dialog *dialog;
2055{
2056  const struct dialog_control *control;
2057
2058  fprintf (e, "STYLE 0x%lx\n", dialog->style);
2059
2060  if (dialog->exstyle != 0)
2061    fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
2062
2063  if ((dialog->class.named && dialog->class.u.n.length > 0)
2064      || dialog->class.u.id != 0)
2065    {
2066      fprintf (e, "CLASS ");
2067      res_id_print (e, dialog->class, 1);
2068      fprintf (e, "\n");
2069    }
2070
2071  if (dialog->caption != NULL)
2072    {
2073      fprintf (e, "CAPTION \"");
2074      unicode_print (e, dialog->caption, -1);
2075      fprintf (e, "\"\n");
2076    }
2077
2078  if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2079      || dialog->menu.u.id != 0)
2080    {
2081      fprintf (e, "MENU ");
2082      res_id_print (e, dialog->menu, 0);
2083      fprintf (e, "\n");
2084    }
2085
2086  if (dialog->font != NULL)
2087    {
2088      fprintf (e, "FONT %d, \"", dialog->pointsize);
2089      unicode_print (e, dialog->font, -1);
2090      fprintf (e, "\"");
2091      if (dialog->ex != NULL
2092	  && (dialog->ex->weight != 0
2093	      || dialog->ex->italic != 0
2094	      || dialog->ex->charset != 1))
2095	fprintf (e, ", %d, %d, %d",
2096		 dialog->ex->weight, dialog->ex->italic, dialog->ex->charset);
2097      fprintf (e, "\n");
2098    }
2099
2100  fprintf (e, "BEGIN\n");
2101
2102  for (control = dialog->controls; control != NULL; control = control->next)
2103    write_rc_dialog_control (e, control);
2104
2105  fprintf (e, "END\n");
2106}
2107
2108/* For each predefined control keyword, this table provides the class
2109   and the style.  */
2110
2111struct control_info
2112{
2113  const char *name;
2114  unsigned short class;
2115  unsigned long style;
2116};
2117
2118static const struct control_info control_info[] =
2119{
2120  { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2121  { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2122  { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2123  { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2124  { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2125  { "CTEXT", CTL_STATIC, SS_CENTER },
2126  { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2127  { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2128  { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2129  { "ICON", CTL_STATIC, SS_ICON },
2130  { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2131  { "LTEXT", CTL_STATIC, SS_LEFT },
2132  { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2133  { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2134  { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2135  { "RTEXT", CTL_STATIC, SS_RIGHT },
2136  { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2137  { "STATE3", CTL_BUTTON, BS_3STATE },
2138  /* It's important that USERBUTTON come after all the other button
2139     types, so that it won't be matched too early.  */
2140  { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2141  { NULL, 0, 0 }
2142};
2143
2144/* Write a dialog control.  */
2145
2146static void
2147write_rc_dialog_control (e, control)
2148     FILE *e;
2149     const struct dialog_control *control;
2150{
2151  const struct control_info *ci;
2152
2153  fprintf (e, "  ");
2154
2155  if (control->class.named)
2156    ci = NULL;
2157  else
2158    {
2159      for (ci = control_info; ci->name != NULL; ++ci)
2160	if (ci->class == control->class.u.id
2161	    && (ci->style == (unsigned long) -1
2162		|| ci->style == (control->style & 0xff)))
2163	  break;
2164    }
2165  if (ci == NULL)
2166    fprintf (e, "CONTROL");
2167  else if (ci->name != NULL)
2168    fprintf (e, "%s", ci->name);
2169  else
2170    fprintf (e, "CONTROL");
2171
2172  if (control->text.named || control->text.u.id != 0)
2173    {
2174      fprintf (e, " ");
2175      res_id_print (e, control->text, 1);
2176      fprintf (e, ",");
2177    }
2178
2179  fprintf (e, " %d, ", control->id);
2180
2181  if (ci == NULL)
2182    {
2183      if (control->class.named)
2184	fprintf (e, "\"");
2185      res_id_print (e, control->class, 0);
2186      if (control->class.named)
2187	fprintf (e, "\"");
2188      fprintf (e, ", 0x%lx, ", control->style);
2189    }
2190
2191  fprintf (e, "%d, %d", control->x, control->y);
2192
2193  if (control->style != SS_ICON
2194      || control->exstyle != 0
2195      || control->width != 0
2196      || control->height != 0
2197      || control->help != 0)
2198    {
2199      fprintf (e, ", %d, %d", control->width, control->height);
2200
2201      /* FIXME: We don't need to print the style if it is the default.
2202	 More importantly, in certain cases we actually need to turn
2203	 off parts of the forced style, by using NOT.  */
2204      fprintf (e, ", 0x%lx", control->style);
2205
2206      if (control->exstyle != 0 || control->help != 0)
2207	fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
2208    }
2209
2210  fprintf (e, "\n");
2211
2212  if (control->data != NULL)
2213    write_rc_rcdata (e, control->data, 2);
2214}
2215
2216/* Write out font directory data.  This would normally be built from
2217   the font data.  */
2218
2219static void
2220write_rc_fontdir (e, fontdir)
2221     FILE *e;
2222     const struct fontdir *fontdir;
2223{
2224  const struct fontdir *fc;
2225
2226  for (fc = fontdir; fc != NULL; fc = fc->next)
2227    {
2228      fprintf (e, "// Font index: %d\n", fc->index);
2229      write_rc_filedata (e, fc->length, fc->data);
2230    }
2231}
2232
2233/* Write out group icon data.  This would normally be built from the
2234   icon data.  */
2235
2236static void
2237write_rc_group_icon (e, group_icon)
2238     FILE *e;
2239     const struct group_icon *group_icon;
2240{
2241  const struct group_icon *gi;
2242
2243  for (gi = group_icon; gi != NULL; gi = gi->next)
2244    {
2245      fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
2246	       gi->width, gi->height, gi->colors, gi->planes, gi->bits);
2247      fprintf (e, "// data bytes: %lu; index: %d\n",
2248	       gi->bytes, gi->index);
2249    }
2250}
2251
2252/* Write out a menu resource.  */
2253
2254static void
2255write_rc_menu (e, menu, menuex)
2256     FILE *e;
2257     const struct menu *menu;
2258     int menuex;
2259{
2260  if (menu->help != 0)
2261    fprintf (e, "// Help ID: %lu\n", menu->help);
2262  write_rc_menuitems (e, menu->items, menuex, 0);
2263}
2264
2265/* Write out menuitems.  */
2266
2267static void
2268write_rc_menuitems (e, menuitems, menuex, ind)
2269     FILE *e;
2270     const struct menuitem *menuitems;
2271     int menuex;
2272     int ind;
2273{
2274  const struct menuitem *mi;
2275
2276  indent (e, ind);
2277  fprintf (e, "BEGIN\n");
2278
2279  for (mi = menuitems; mi != NULL; mi = mi->next)
2280    {
2281      indent (e, ind + 2);
2282
2283      if (mi->popup == NULL)
2284	fprintf (e, "MENUITEM");
2285      else
2286	fprintf (e, "POPUP");
2287
2288      if (! menuex
2289	  && mi->popup == NULL
2290	  && mi->text == NULL
2291	  && mi->type == 0
2292	  && mi->id == 0)
2293	{
2294	  fprintf (e, " SEPARATOR\n");
2295	  continue;
2296	}
2297
2298      if (mi->text == NULL)
2299	fprintf (e, " \"\"");
2300      else
2301	{
2302	  fprintf (e, " \"");
2303	  unicode_print (e, mi->text, -1);
2304	  fprintf (e, "\"");
2305	}
2306
2307      if (! menuex)
2308	{
2309	  if (mi->popup == NULL)
2310	    fprintf (e, ", %d", mi->id);
2311
2312	  if ((mi->type & MENUITEM_CHECKED) != 0)
2313	    fprintf (e, ", CHECKED");
2314	  if ((mi->type & MENUITEM_GRAYED) != 0)
2315	    fprintf (e, ", GRAYED");
2316	  if ((mi->type & MENUITEM_HELP) != 0)
2317	    fprintf (e, ", HELP");
2318	  if ((mi->type & MENUITEM_INACTIVE) != 0)
2319	    fprintf (e, ", INACTIVE");
2320	  if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2321	    fprintf (e, ", MENUBARBREAK");
2322	  if ((mi->type & MENUITEM_MENUBREAK) != 0)
2323	    fprintf (e, ", MENUBREAK");
2324	}
2325      else
2326	{
2327	  if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2328	    {
2329	      fprintf (e, ", %d", mi->id);
2330	      if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2331		{
2332		  fprintf (e, ", %lu", mi->type);
2333		  if (mi->state != 0 || mi->help != 0)
2334		    {
2335		      fprintf (e, ", %lu", mi->state);
2336		      if (mi->help != 0)
2337			fprintf (e, ", %lu", mi->help);
2338		    }
2339		}
2340	    }
2341	}
2342
2343      fprintf (e, "\n");
2344
2345      if (mi->popup != NULL)
2346	write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2347    }
2348
2349  indent (e, ind);
2350  fprintf (e, "END\n");
2351}
2352
2353/* Write out an rcdata resource.  This is also used for other types of
2354   resources that need to print arbitrary data.  */
2355
2356static void
2357write_rc_rcdata (e, rcdata, ind)
2358     FILE *e;
2359     const struct rcdata_item *rcdata;
2360     int ind;
2361{
2362  const struct rcdata_item *ri;
2363
2364  indent (e, ind);
2365  fprintf (e, "BEGIN\n");
2366
2367  for (ri = rcdata; ri != NULL; ri = ri->next)
2368    {
2369      if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
2370	continue;
2371
2372      indent (e, ind + 2);
2373
2374      switch (ri->type)
2375	{
2376	default:
2377	  abort ();
2378
2379	case RCDATA_WORD:
2380	  fprintf (e, "%d", ri->u.word);
2381	  break;
2382
2383	case RCDATA_DWORD:
2384	  fprintf (e, "%luL", ri->u.dword);
2385	  break;
2386
2387	case RCDATA_STRING:
2388	  {
2389	    const char *s;
2390	    unsigned long i;
2391
2392	    fprintf (e, "\"");
2393	    s = ri->u.string.s;
2394	    for (i = 0; i < ri->u.string.length; i++)
2395	      {
2396		if (ISPRINT (*s))
2397		  putc (*s, e);
2398		else
2399		  fprintf (e, "\\%03o", *s);
2400	      }
2401	    fprintf (e, "\"");
2402	    break;
2403	  }
2404
2405	case RCDATA_WSTRING:
2406	  fprintf (e, "L\"");
2407	  unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
2408	  fprintf (e, "\"");
2409	  break;
2410
2411	case RCDATA_BUFFER:
2412	  {
2413	    unsigned long i;
2414	    int first;
2415
2416	    /* Assume little endian data.  */
2417
2418	    first = 1;
2419	    for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
2420	      {
2421		unsigned long l;
2422		int j;
2423
2424		if (! first)
2425		  indent (e, ind + 2);
2426		l = ((((((ri->u.buffer.data[i + 3] << 8)
2427			 | ri->u.buffer.data[i + 2]) << 8)
2428		       | ri->u.buffer.data[i + 1]) << 8)
2429		     | ri->u.buffer.data[i]);
2430		fprintf (e, "%luL", l);
2431		if (i + 4 < ri->u.buffer.length || ri->next != NULL)
2432		  fprintf (e, ",");
2433		for (j = 0; j < 4; ++j)
2434		  if (! ISPRINT (ri->u.buffer.data[i + j])
2435		      && ri->u.buffer.data[i + j] != 0)
2436		    break;
2437		if (j >= 4)
2438		  {
2439		    fprintf (e, "\t// ");
2440		    for (j = 0; j < 4; ++j)
2441		      {
2442			if (! ISPRINT (ri->u.buffer.data[i + j]))
2443			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2444			else
2445			  {
2446			    if (ri->u.buffer.data[i + j] == '\\')
2447			      fprintf (e, "\\");
2448			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
2449			  }
2450		      }
2451		  }
2452		fprintf (e, "\n");
2453		first = 0;
2454	      }
2455
2456	    if (i + 1 < ri->u.buffer.length)
2457	      {
2458		int s;
2459		int j;
2460
2461		if (! first)
2462		  indent (e, ind + 2);
2463		s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
2464		fprintf (e, "%d", s);
2465		if (i + 2 < ri->u.buffer.length || ri->next != NULL)
2466		  fprintf (e, ",");
2467		for (j = 0; j < 2; ++j)
2468		  if (! ISPRINT (ri->u.buffer.data[i + j])
2469		      && ri->u.buffer.data[i + j] != 0)
2470		    break;
2471		if (j >= 2)
2472		  {
2473		    fprintf (e, "\t// ");
2474		    for (j = 0; j < 2; ++j)
2475		      {
2476			if (! ISPRINT (ri->u.buffer.data[i + j]))
2477			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2478			else
2479			  {
2480			    if (ri->u.buffer.data[i + j] == '\\')
2481			      fprintf (e, "\\");
2482			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
2483			  }
2484		      }
2485		  }
2486		fprintf (e, "\n");
2487		i += 2;
2488		first = 0;
2489	      }
2490
2491	    if (i < ri->u.buffer.length)
2492	      {
2493		if (! first)
2494		  indent (e, ind + 2);
2495		if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
2496		    && ISPRINT (ri->u.buffer.data[i]))
2497		  fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
2498		else
2499		  fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
2500		if (ri->next != NULL)
2501		  fprintf (e, ",");
2502		fprintf (e, "\n");
2503		first = 0;
2504	      }
2505
2506	    break;
2507	  }
2508	}
2509
2510      if (ri->type != RCDATA_BUFFER)
2511	{
2512	  if (ri->next != NULL)
2513	    fprintf (e, ",");
2514	  fprintf (e, "\n");
2515	}
2516    }
2517
2518  indent (e, ind);
2519  fprintf (e, "END\n");
2520}
2521
2522/* Write out a stringtable resource.  */
2523
2524static void
2525write_rc_stringtable (e, name, stringtable)
2526     FILE *e;
2527     const struct res_id *name;
2528     const struct stringtable *stringtable;
2529{
2530  unsigned long offset;
2531  int i;
2532
2533  if (name != NULL && ! name->named)
2534    offset = (name->u.id - 1) << 4;
2535  else
2536    {
2537      fprintf (e, "// %s string table name\n",
2538	       name == NULL ? "Missing" : "Invalid");
2539      offset = 0;
2540    }
2541
2542  fprintf (e, "BEGIN\n");
2543
2544  for (i = 0; i < 16; i++)
2545    {
2546      if (stringtable->strings[i].length != 0)
2547	{
2548	  fprintf (e, "  %lu, \"", offset + i);
2549	  unicode_print (e, stringtable->strings[i].string,
2550			 stringtable->strings[i].length);
2551	  fprintf (e, "\"\n");
2552	}
2553    }
2554
2555  fprintf (e, "END\n");
2556}
2557
2558/* Write out a versioninfo resource.  */
2559
2560static void
2561write_rc_versioninfo (e, versioninfo)
2562     FILE *e;
2563     const struct versioninfo *versioninfo;
2564{
2565  const struct fixed_versioninfo *f;
2566  const struct ver_info *vi;
2567
2568  f = versioninfo->fixed;
2569  if (f->file_version_ms != 0 || f->file_version_ls != 0)
2570    fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
2571	     (f->file_version_ms >> 16) & 0xffff,
2572	     f->file_version_ms & 0xffff,
2573	     (f->file_version_ls >> 16) & 0xffff,
2574	     f->file_version_ls & 0xffff);
2575  if (f->product_version_ms != 0 || f->product_version_ls != 0)
2576    fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
2577	     (f->product_version_ms >> 16) & 0xffff,
2578	     f->product_version_ms & 0xffff,
2579	     (f->product_version_ls >> 16) & 0xffff,
2580	     f->product_version_ls & 0xffff);
2581  if (f->file_flags_mask != 0)
2582    fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
2583  if (f->file_flags != 0)
2584    fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
2585  if (f->file_os != 0)
2586    fprintf (e, " FILEOS 0x%lx\n", f->file_os);
2587  if (f->file_type != 0)
2588    fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
2589  if (f->file_subtype != 0)
2590    fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
2591  if (f->file_date_ms != 0 || f->file_date_ls != 0)
2592    fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
2593
2594  fprintf (e, "BEGIN\n");
2595
2596  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2597    {
2598      switch (vi->type)
2599	{
2600	case VERINFO_STRING:
2601	  {
2602	    const struct ver_stringinfo *vs;
2603
2604	    fprintf (e, "  BLOCK \"StringFileInfo\"\n");
2605	    fprintf (e, "  BEGIN\n");
2606	    fprintf (e, "    BLOCK \"");
2607	    unicode_print (e, vi->u.string.language, -1);
2608	    fprintf (e, "\"\n");
2609	    fprintf (e, "    BEGIN\n");
2610
2611	    for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2612	      {
2613		fprintf (e, "      VALUE \"");
2614		unicode_print (e, vs->key, -1);
2615		fprintf (e, "\", \"");
2616		unicode_print (e, vs->value, -1);
2617		fprintf (e, "\"\n");
2618	      }
2619
2620	    fprintf (e, "    END\n");
2621	    fprintf (e, "  END\n");
2622	    break;
2623	  }
2624
2625	case VERINFO_VAR:
2626	  {
2627	    const struct ver_varinfo *vv;
2628
2629	    fprintf (e, "  BLOCK \"VarFileInfo\"\n");
2630	    fprintf (e, "  BEGIN\n");
2631	    fprintf (e, "    VALUE \"");
2632	    unicode_print (e, vi->u.var.key, -1);
2633	    fprintf (e, "\"");
2634
2635	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2636	      fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
2637		       vv->charset);
2638
2639	    fprintf (e, "\n  END\n");
2640
2641	    break;
2642	  }
2643	}
2644    }
2645
2646  fprintf (e, "END\n");
2647}
2648
2649/* Write out data which would normally be read from a file.  */
2650
2651static void
2652write_rc_filedata (e, length, data)
2653     FILE *e;
2654     unsigned long length;
2655     const unsigned char *data;
2656{
2657  unsigned long i;
2658
2659  for (i = 0; i + 15 < length; i += 16)
2660    {
2661      fprintf (e, "// %4lx: ", i);
2662      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
2663	       data[i + 0], data[i + 1], data[i + 2], data[i + 3],
2664	       data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
2665      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2666	       data[i +  8], data[i +  9], data[i + 10], data[i + 11],
2667	       data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
2668    }
2669
2670  if (i < length)
2671    {
2672      fprintf (e, "// %4lx:", i);
2673      while (i < length)
2674	{
2675	  fprintf (e, " %02x", data[i]);
2676	  ++i;
2677	}
2678      fprintf (e, "\n");
2679    }
2680}
2681