resrc.c revision 104834
1/* resrc.c -- read and write Windows rc files.
2   Copyright 1997, 1998, 1999, 2000, 2001, 2002 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  char *temp_base = choose_temp_base ();
189  int in_quote;
190  char sep;
191  int redir_handle = -1;
192  int stdout_save = -1;
193
194  /* Count the args.  */
195  i = 0;
196
197  for (s = cmd; *s; s++)
198    if (*s == ' ')
199      i++;
200
201  i++;
202  argv = alloca (sizeof (char *) * (i + 3));
203  i = 0;
204  s = cmd;
205
206  while (1)
207    {
208      while (*s == ' ' && *s != 0)
209	s++;
210
211      if (*s == 0)
212	break;
213
214      in_quote = (*s == '\'' || *s == '"');
215      sep = (in_quote) ? *s++ : ' ';
216      argv[i++] = s;
217
218      while (*s != sep && *s != 0)
219	s++;
220
221      if (*s == 0)
222	break;
223
224      *s++ = 0;
225
226      if (in_quote)
227	s++;
228    }
229  argv[i++] = NULL;
230
231  /* Setup the redirection.  We can't use the usual fork/exec and redirect
232     since we may be running on non-POSIX Windows host.  */
233
234  fflush (stdout);
235  fflush (stderr);
236
237  /* Open temporary output file.  */
238  redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
239  if (redir_handle == -1)
240    fatal (_("can't open temporary file `%s': %s"), redir,
241	   strerror (errno));
242
243  /* Duplicate the stdout file handle so it can be restored later.  */
244  stdout_save = dup (STDOUT_FILENO);
245  if (stdout_save == -1)
246    fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
247
248  /* Redirect stdout to our output file.  */
249  dup2 (redir_handle, STDOUT_FILENO);
250
251  pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
252		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
253
254  /* Restore stdout to its previous setting.  */
255  dup2 (stdout_save, STDOUT_FILENO);
256
257  /* Close reponse file.  */
258  close (redir_handle);
259
260  if (pid == -1)
261    {
262      fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
263      return 1;
264    }
265
266  retcode = 0;
267  pid = pwait (pid, &wait_status, 0);
268
269  if (pid == -1)
270    {
271      fatal (_("wait: %s"), strerror (errno));
272      retcode = 1;
273    }
274  else if (WIFSIGNALED (wait_status))
275    {
276      fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
277      retcode = 1;
278    }
279  else if (WIFEXITED (wait_status))
280    {
281      if (WEXITSTATUS (wait_status) != 0)
282	{
283	  fatal (_("%s exited with status %d"), cmd,
284	         WEXITSTATUS (wait_status));
285	  retcode = 1;
286	}
287    }
288  else
289    retcode = 1;
290
291  return retcode;
292}
293
294static FILE *
295open_input_stream (cmd)
296     char *cmd;
297{
298  if (istream_type == ISTREAM_FILE)
299    {
300      char *fileprefix;
301
302      fileprefix = choose_temp_base ();
303      cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
304      sprintf (cpp_temp_file, "%s.irc", fileprefix);
305      free (fileprefix);
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 (text, id, x, y, width, height, class, style, exstyle)
822     const char *text;
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  if (text == NULL)
846    text = "";
847  res_string_to_id (&n->text, text);
848  n->data = NULL;
849  n->help = 0;
850
851  return n;
852}
853
854struct dialog_control *
855define_icon_control (iid, id, x, y, style, exstyle, help, data, ex)
856     struct res_id iid;
857     unsigned long id;
858     unsigned long x;
859     unsigned long y;
860     unsigned long style;
861     unsigned long exstyle;
862     unsigned long help;
863     struct rcdata_item *data;
864     struct dialog_ex *ex;
865{
866  struct dialog_control *n;
867  if (style == 0)
868    style = SS_ICON | WS_CHILD | WS_VISIBLE;
869  n = define_control (0, id, x, y, 0, 0, CTL_STATIC, style, exstyle);
870  n->text = iid;
871  if (help && !ex)
872    rcparse_warning (_("help ID requires DIALOGEX"));
873  if (data && !ex)
874    rcparse_warning (_("control data requires DIALOGEX"));
875  n->help = help;
876  n->data = data;
877
878  return n;
879}
880
881/* Define a font resource.  */
882
883void
884define_font (id, resinfo, filename)
885     struct res_id id;
886     const struct res_res_info *resinfo;
887     const char *filename;
888{
889  FILE *e;
890  char *real_filename;
891  struct stat s;
892  unsigned char *data;
893  struct res_resource *r;
894  long offset;
895  long fontdatalength;
896  unsigned char *fontdata;
897  struct fontdir *fd;
898  const char *device, *face;
899  struct fontdir **pp;
900
901  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
902
903  if (stat (real_filename, &s) < 0)
904    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
905	   strerror (errno));
906
907  data = (unsigned char *) res_alloc (s.st_size);
908
909  get_data (e, data, s.st_size, real_filename);
910
911  fclose (e);
912  free (real_filename);
913
914  r = define_standard_resource (&resources, RT_FONT, id,
915				resinfo->language, 0);
916
917  r->type = RES_TYPE_FONT;
918  r->u.data.length = s.st_size;
919  r->u.data.data = data;
920  r->res_info = *resinfo;
921
922  /* For each font resource, we must add an entry in the FONTDIR
923     resource.  The FONTDIR resource includes some strings in the font
924     file.  To find them, we have to do some magic on the data we have
925     read.  */
926
927  offset = ((((((data[47] << 8)
928		| data[46]) << 8)
929	      | data[45]) << 8)
930	    | data[44]);
931  if (offset > 0 && offset < s.st_size)
932    device = (char *) data + offset;
933  else
934    device = "";
935
936  offset = ((((((data[51] << 8)
937		| data[50]) << 8)
938	      | data[49]) << 8)
939	    | data[48]);
940  if (offset > 0 && offset < s.st_size)
941    face = (char *) data + offset;
942  else
943    face = "";
944
945  ++fonts;
946
947  fontdatalength = 58 + strlen (device) + strlen (face);
948  fontdata = (unsigned char *) res_alloc (fontdatalength);
949  memcpy (fontdata, data, 56);
950  strcpy ((char *) fontdata + 56, device);
951  strcpy ((char *) fontdata + 57 + strlen (device), face);
952
953  fd = (struct fontdir *) res_alloc (sizeof *fd);
954  fd->next = NULL;
955  fd->index = fonts;
956  fd->length = fontdatalength;
957  fd->data = fontdata;
958
959  for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
960    ;
961  *pp = fd;
962
963  /* For the single fontdirs resource, we always use the resource
964     information of the last font.  I don't know what else to do.  */
965  fontdirs_resinfo = *resinfo;
966}
967
968/* Define the fontdirs resource.  This is called after the entire rc
969   file has been parsed, if any font resources were seen.  */
970
971static void
972define_fontdirs ()
973{
974  struct res_resource *r;
975  struct res_id id;
976
977  id.named = 0;
978  id.u.id = 1;
979
980  r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
981
982  r->type = RES_TYPE_FONTDIR;
983  r->u.fontdir = fontdirs;
984  r->res_info = fontdirs_resinfo;
985}
986
987/* Define an icon resource.  An icon file may contain a set of
988   bitmaps, each representing the same icon at various different
989   resolutions.  They each get written out with a different ID.  The
990   real icon resource is then a group resource which can be used to
991   select one of the actual icon bitmaps.  */
992
993void
994define_icon (id, resinfo, filename)
995     struct res_id id;
996     const struct res_res_info *resinfo;
997     const char *filename;
998{
999  FILE *e;
1000  char *real_filename;
1001  int type, count, i;
1002  struct icondir *icondirs;
1003  int first_icon;
1004  struct res_resource *r;
1005  struct group_icon *first, **pp;
1006
1007  e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
1008
1009  /* The start of an icon file is a three word structure.  The first
1010     word is ignored.  The second word is the type of data.  The third
1011     word is the number of entries.  */
1012
1013  get_word (e, real_filename);
1014  type = get_word (e, real_filename);
1015  count = get_word (e, real_filename);
1016  if (type != 1)
1017    fatal (_("icon file `%s' does not contain icon data"), real_filename);
1018
1019  /* Read in the icon directory entries.  */
1020
1021  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
1022
1023  for (i = 0; i < count; i++)
1024    {
1025      icondirs[i].width = getc (e);
1026      icondirs[i].height = getc (e);
1027      icondirs[i].colorcount = getc (e);
1028      getc (e);
1029      icondirs[i].u.icon.planes = get_word (e, real_filename);
1030      icondirs[i].u.icon.bits = get_word (e, real_filename);
1031      icondirs[i].bytes = get_long (e, real_filename);
1032      icondirs[i].offset = get_long (e, real_filename);
1033
1034      if (feof (e))
1035	unexpected_eof (real_filename);
1036    }
1037
1038  /* Define each icon as a unique resource.  */
1039
1040  first_icon = icons;
1041
1042  for (i = 0; i < count; i++)
1043    {
1044      unsigned char *data;
1045      struct res_id name;
1046
1047      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
1048	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
1049	       icondirs[i].offset, strerror (errno));
1050
1051      data = (unsigned char *) res_alloc (icondirs[i].bytes);
1052
1053      get_data (e, data, icondirs[i].bytes, real_filename);
1054
1055      ++icons;
1056
1057      name.named = 0;
1058      name.u.id = icons;
1059
1060      r = define_standard_resource (&resources, RT_ICON, name,
1061				    resinfo->language, 0);
1062      r->type = RES_TYPE_ICON;
1063      r->u.data.length = icondirs[i].bytes;
1064      r->u.data.data = data;
1065      r->res_info = *resinfo;
1066    }
1067
1068  fclose (e);
1069  free (real_filename);
1070
1071  /* Define an icon group resource.  */
1072
1073  first = NULL;
1074  pp = &first;
1075  for (i = 0; i < count; i++)
1076    {
1077      struct group_icon *cg;
1078
1079      /* For some reason, at least in some files the planes and bits
1080         are zero.  We instead set them from the color.  This is
1081         copied from rcl.  */
1082
1083      cg = (struct group_icon *) res_alloc (sizeof *cg);
1084      cg->next = NULL;
1085      cg->width = icondirs[i].width;
1086      cg->height = icondirs[i].height;
1087      cg->colors = icondirs[i].colorcount;
1088
1089      cg->planes = 1;
1090      cg->bits = 0;
1091      while ((1 << cg->bits) < cg->colors)
1092	++cg->bits;
1093
1094      cg->bytes = icondirs[i].bytes;
1095      cg->index = first_icon + i + 1;
1096
1097      *pp = cg;
1098      pp = &(*pp)->next;
1099    }
1100
1101  free (icondirs);
1102
1103  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1104				resinfo->language, 0);
1105  r->type = RES_TYPE_GROUP_ICON;
1106  r->u.group_icon = first;
1107  r->res_info = *resinfo;
1108}
1109
1110/* Define a menu resource.  */
1111
1112void
1113define_menu (id, resinfo, menuitems)
1114     struct res_id id;
1115     const struct res_res_info *resinfo;
1116     struct menuitem *menuitems;
1117{
1118  struct menu *m;
1119  struct res_resource *r;
1120
1121  m = (struct menu *) res_alloc (sizeof *m);
1122  m->items = menuitems;
1123  m->help = 0;
1124
1125  r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1126  r->type = RES_TYPE_MENU;
1127  r->u.menu = m;
1128  r->res_info = *resinfo;
1129}
1130
1131/* Define a menu item.  This does not define a resource, but merely
1132   allocates and fills in a structure.  */
1133
1134struct menuitem *
1135define_menuitem (text, menuid, type, state, help, menuitems)
1136     const char *text;
1137     int menuid;
1138     unsigned long type;
1139     unsigned long state;
1140     unsigned long help;
1141     struct menuitem *menuitems;
1142{
1143  struct menuitem *mi;
1144
1145  mi = (struct menuitem *) res_alloc (sizeof *mi);
1146  mi->next = NULL;
1147  mi->type = type;
1148  mi->state = state;
1149  mi->id = menuid;
1150  if (text == NULL)
1151    mi->text = NULL;
1152  else
1153    unicode_from_ascii ((int *) NULL, &mi->text, text);
1154  mi->help = help;
1155  mi->popup = menuitems;
1156  return mi;
1157}
1158
1159/* Define a messagetable resource.  */
1160
1161void
1162define_messagetable (id, resinfo, filename)
1163     struct res_id id;
1164     const struct res_res_info *resinfo;
1165     const char *filename;
1166{
1167  FILE *e;
1168  char *real_filename;
1169  struct stat s;
1170  unsigned char *data;
1171  struct res_resource *r;
1172
1173  e = open_file_search (filename, FOPEN_RB, "messagetable file",
1174			&real_filename);
1175
1176  if (stat (real_filename, &s) < 0)
1177    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1178	   strerror (errno));
1179
1180  data = (unsigned char *) res_alloc (s.st_size);
1181
1182  get_data (e, data, s.st_size, real_filename);
1183
1184  fclose (e);
1185  free (real_filename);
1186
1187  r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1188				resinfo->language, 0);
1189
1190  r->type = RES_TYPE_MESSAGETABLE;
1191  r->u.data.length = s.st_size;
1192  r->u.data.data = data;
1193  r->res_info = *resinfo;
1194}
1195
1196/* Define an rcdata resource.  */
1197
1198void
1199define_rcdata (id, resinfo, data)
1200     struct res_id id;
1201     const struct res_res_info *resinfo;
1202     struct rcdata_item *data;
1203{
1204  struct res_resource *r;
1205
1206  r = define_standard_resource (&resources, RT_RCDATA, id,
1207				resinfo->language, 0);
1208  r->type = RES_TYPE_RCDATA;
1209  r->u.rcdata = data;
1210  r->res_info = *resinfo;
1211}
1212
1213/* Create an rcdata item holding a string.  */
1214
1215struct rcdata_item *
1216define_rcdata_string (string, len)
1217     const char *string;
1218     unsigned long len;
1219{
1220  struct rcdata_item *ri;
1221  char *s;
1222
1223  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
1224  ri->next = NULL;
1225  ri->type = RCDATA_STRING;
1226  ri->u.string.length = len;
1227  s = (char *) res_alloc (len);
1228  memcpy (s, string, len);
1229  ri->u.string.s = s;
1230
1231  return ri;
1232}
1233
1234/* Create an rcdata item holding a number.  */
1235
1236struct rcdata_item *
1237define_rcdata_number (val, dword)
1238     unsigned long val;
1239     int dword;
1240{
1241  struct rcdata_item *ri;
1242
1243  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
1244  ri->next = NULL;
1245  ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1246  ri->u.word = val;
1247
1248  return ri;
1249}
1250
1251/* Define a stringtable resource.  This is called for each string
1252   which appears in a STRINGTABLE statement.  */
1253
1254void
1255define_stringtable (resinfo, stringid, string)
1256     const struct res_res_info *resinfo;
1257     unsigned long stringid;
1258     const char *string;
1259{
1260  struct res_id id;
1261  struct res_resource *r;
1262
1263  id.named = 0;
1264  id.u.id = (stringid >> 4) + 1;
1265  r = define_standard_resource (&resources, RT_STRING, id,
1266				resinfo->language, 1);
1267
1268  if (r->type == RES_TYPE_UNINITIALIZED)
1269    {
1270      int i;
1271
1272      r->type = RES_TYPE_STRINGTABLE;
1273      r->u.stringtable = ((struct stringtable *)
1274			  res_alloc (sizeof (struct stringtable)));
1275      for (i = 0; i < 16; i++)
1276	{
1277	  r->u.stringtable->strings[i].length = 0;
1278	  r->u.stringtable->strings[i].string = NULL;
1279	}
1280
1281      r->res_info = *resinfo;
1282    }
1283
1284  unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
1285		      &r->u.stringtable->strings[stringid & 0xf].string,
1286		      string);
1287}
1288
1289/* Define a user data resource where the data is in the rc file.  */
1290
1291void
1292define_user_data (id, type, resinfo, data)
1293     struct res_id id;
1294     struct res_id type;
1295     const struct res_res_info *resinfo;
1296     struct rcdata_item *data;
1297{
1298  struct res_id ids[3];
1299  struct res_resource *r;
1300
1301  ids[0] = type;
1302  ids[1] = id;
1303  ids[2].named = 0;
1304  ids[2].u.id = resinfo->language;
1305
1306  r = define_resource (&resources, 3, ids, 0);
1307  r->type = RES_TYPE_USERDATA;
1308  r->u.userdata = data;
1309  r->res_info = *resinfo;
1310}
1311
1312/* Define a user data resource where the data is in a file.  */
1313
1314void
1315define_user_file (id, type, resinfo, filename)
1316     struct res_id id;
1317     struct res_id type;
1318     const struct res_res_info *resinfo;
1319     const char *filename;
1320{
1321  FILE *e;
1322  char *real_filename;
1323  struct stat s;
1324  unsigned char *data;
1325  struct res_id ids[3];
1326  struct res_resource *r;
1327
1328  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
1329
1330  if (stat (real_filename, &s) < 0)
1331    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1332	   strerror (errno));
1333
1334  data = (unsigned char *) res_alloc (s.st_size);
1335
1336  get_data (e, data, s.st_size, real_filename);
1337
1338  fclose (e);
1339  free (real_filename);
1340
1341  ids[0] = type;
1342  ids[1] = id;
1343  ids[2].named = 0;
1344  ids[2].u.id = resinfo->language;
1345
1346  r = define_resource (&resources, 3, ids, 0);
1347  r->type = RES_TYPE_USERDATA;
1348  r->u.userdata = ((struct rcdata_item *)
1349		   res_alloc (sizeof (struct rcdata_item)));
1350  r->u.userdata->next = NULL;
1351  r->u.userdata->type = RCDATA_BUFFER;
1352  r->u.userdata->u.buffer.length = s.st_size;
1353  r->u.userdata->u.buffer.data = data;
1354  r->res_info = *resinfo;
1355}
1356
1357/* Define a versioninfo resource.  */
1358
1359void
1360define_versioninfo (id, language, fixedverinfo, verinfo)
1361     struct res_id id;
1362     int language;
1363     struct fixed_versioninfo *fixedverinfo;
1364     struct ver_info *verinfo;
1365{
1366  struct res_resource *r;
1367
1368  r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1369  r->type = RES_TYPE_VERSIONINFO;
1370  r->u.versioninfo = ((struct versioninfo *)
1371		      res_alloc (sizeof (struct versioninfo)));
1372  r->u.versioninfo->fixed = fixedverinfo;
1373  r->u.versioninfo->var = verinfo;
1374  r->res_info.language = language;
1375}
1376
1377/* Add string version info to a list of version information.  */
1378
1379struct ver_info *
1380append_ver_stringfileinfo (verinfo, language, strings)
1381     struct ver_info *verinfo;
1382     const char *language;
1383     struct ver_stringinfo *strings;
1384{
1385  struct ver_info *vi, **pp;
1386
1387  vi = (struct ver_info *) res_alloc (sizeof *vi);
1388  vi->next = NULL;
1389  vi->type = VERINFO_STRING;
1390  unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
1391  vi->u.string.strings = strings;
1392
1393  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1394    ;
1395  *pp = vi;
1396
1397  return verinfo;
1398}
1399
1400/* Add variable version info to a list of version information.  */
1401
1402struct ver_info *
1403append_ver_varfileinfo (verinfo, key, var)
1404     struct ver_info *verinfo;
1405     const char *key;
1406     struct ver_varinfo *var;
1407{
1408  struct ver_info *vi, **pp;
1409
1410  vi = (struct ver_info *) res_alloc (sizeof *vi);
1411  vi->next = NULL;
1412  vi->type = VERINFO_VAR;
1413  unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
1414  vi->u.var.var = var;
1415
1416  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1417    ;
1418  *pp = vi;
1419
1420  return verinfo;
1421}
1422
1423/* Append version string information to a list.  */
1424
1425struct ver_stringinfo *
1426append_verval (strings, key, value)
1427     struct ver_stringinfo *strings;
1428     const char *key;
1429     const char *value;
1430{
1431  struct ver_stringinfo *vs, **pp;
1432
1433  vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
1434  vs->next = NULL;
1435  unicode_from_ascii ((int *) NULL, &vs->key, key);
1436  unicode_from_ascii ((int *) NULL, &vs->value, value);
1437
1438  for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1439    ;
1440  *pp = vs;
1441
1442  return strings;
1443}
1444
1445/* Append version variable information to a list.  */
1446
1447struct ver_varinfo *
1448append_vertrans (var, language, charset)
1449     struct ver_varinfo *var;
1450     unsigned long language;
1451     unsigned long charset;
1452{
1453  struct ver_varinfo *vv, **pp;
1454
1455  vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
1456  vv->next = NULL;
1457  vv->language = language;
1458  vv->charset = charset;
1459
1460  for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1461    ;
1462  *pp = vv;
1463
1464  return var;
1465}
1466
1467/* Local functions used to write out an rc file.  */
1468
1469static void indent PARAMS ((FILE *, int));
1470static void write_rc_directory
1471  PARAMS ((FILE *, const struct res_directory *, const struct res_id *,
1472	   const struct res_id *, int *, int));
1473static void write_rc_subdir
1474  PARAMS ((FILE *, const struct res_entry *, const struct res_id *,
1475	   const struct res_id *, int *, int));
1476static void write_rc_resource
1477  PARAMS ((FILE *, const struct res_id *, const struct res_id *,
1478	   const struct res_resource *, int *));
1479static void write_rc_accelerators
1480  PARAMS ((FILE *, const struct accelerator *));
1481static void write_rc_cursor PARAMS ((FILE *, const struct cursor *));
1482static void write_rc_group_cursor
1483  PARAMS ((FILE *, const struct group_cursor *));
1484static void write_rc_dialog PARAMS ((FILE *, const struct dialog *));
1485static void write_rc_dialog_control
1486  PARAMS ((FILE *, const struct dialog_control *));
1487static void write_rc_fontdir PARAMS ((FILE *, const struct fontdir *));
1488static void write_rc_group_icon PARAMS ((FILE *, const struct group_icon *));
1489static void write_rc_menu PARAMS ((FILE *, const struct menu *, int));
1490static void write_rc_menuitems
1491  PARAMS ((FILE *, const struct menuitem *, int, int));
1492static void write_rc_rcdata PARAMS ((FILE *, const struct rcdata_item *, int));
1493static void write_rc_stringtable
1494  PARAMS ((FILE *, const struct res_id *, const struct stringtable *));
1495static void write_rc_versioninfo PARAMS ((FILE *, const struct versioninfo *));
1496static void write_rc_filedata
1497  PARAMS ((FILE *, unsigned long, const unsigned char *));
1498
1499/* Indent a given number of spaces.  */
1500
1501static void
1502indent (e, c)
1503     FILE *e;
1504     int c;
1505{
1506  int i;
1507
1508  for (i = 0; i < c; i++)
1509    putc (' ', e);
1510}
1511
1512/* Dump the resources we have read in the format of an rc file.
1513
1514   Actually, we don't use the format of an rc file, because it's way
1515   too much of a pain--for example, we'd have to write icon resources
1516   into a file and refer to that file.  We just generate a readable
1517   format that kind of looks like an rc file, and is useful for
1518   understanding the contents of a resource file.  Someday we may want
1519   to generate an rc file which the rc compiler can read; if that day
1520   comes, this code will have to be fixed up.  */
1521
1522void
1523write_rc_file (filename, resources)
1524     const char *filename;
1525     const struct res_directory *resources;
1526{
1527  FILE *e;
1528  int language;
1529
1530  if (filename == NULL)
1531    e = stdout;
1532  else
1533    {
1534      e = fopen (filename, FOPEN_WT);
1535      if (e == NULL)
1536	fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1537    }
1538
1539  language = -1;
1540  write_rc_directory (e, resources, (const struct res_id *) NULL,
1541		      (const struct res_id *) NULL, &language, 1);
1542}
1543
1544/* Write out a directory.  E is the file to write to.  RD is the
1545   directory.  TYPE is a pointer to the level 1 ID which serves as the
1546   resource type.  NAME is a pointer to the level 2 ID which serves as
1547   an individual resource name.  LANGUAGE is a pointer to the current
1548   language.  LEVEL is the level in the tree.  */
1549
1550static void
1551write_rc_directory (e, rd, type, name, language, level)
1552     FILE *e;
1553     const struct res_directory *rd;
1554     const struct res_id *type;
1555     const struct res_id *name;
1556     int *language;
1557     int level;
1558{
1559  const struct res_entry *re;
1560
1561  /* Print out some COFF information that rc files can't represent.  */
1562
1563  if (rd->time != 0)
1564    fprintf (e, "// Time stamp: %lu\n", rd->time);
1565  if (rd->characteristics != 0)
1566    fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
1567  if (rd->major != 0 || rd->minor != 0)
1568    fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
1569
1570  for (re = rd->entries;  re != NULL; re = re->next)
1571    {
1572      switch (level)
1573	{
1574	case 1:
1575	  /* If we're at level 1, the key of this resource is the
1576             type.  This normally duplicates the information we have
1577             stored with the resource itself, but we need to remember
1578             the type if this is a user define resource type.  */
1579	  type = &re->id;
1580	  break;
1581
1582	case 2:
1583	  /* If we're at level 2, the key of this resource is the name
1584	     we are going to use in the rc printout.  */
1585	  name = &re->id;
1586	  break;
1587
1588	case 3:
1589	  /* If we're at level 3, then this key represents a language.
1590	     Use it to update the current language.  */
1591	  if (! re->id.named
1592	      && re->id.u.id != (unsigned long) (unsigned int) *language
1593	      && (re->id.u.id & 0xffff) == re->id.u.id)
1594	    {
1595	      fprintf (e, "LANGUAGE %lu, %lu\n",
1596		       re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
1597		       (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
1598	      *language = re->id.u.id;
1599	    }
1600	  break;
1601
1602	default:
1603	  break;
1604	}
1605
1606      if (re->subdir)
1607	write_rc_subdir (e, re, type, name, language, level);
1608      else
1609	{
1610	  if (level == 3)
1611	    {
1612	      /* This is the normal case: the three levels are
1613                 TYPE/NAME/LANGUAGE.  NAME will have been set at level
1614                 2, and represents the name to use.  We probably just
1615                 set LANGUAGE, and it will probably match what the
1616                 resource itself records if anything.  */
1617	      write_rc_resource (e, type, name, re->u.res, language);
1618	    }
1619	  else
1620	    {
1621	      fprintf (e, "// Resource at unexpected level %d\n", level);
1622	      write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
1623				 language);
1624	    }
1625	}
1626    }
1627}
1628
1629/* Write out a subdirectory entry.  E is the file to write to.  RE is
1630   the subdirectory entry.  TYPE and NAME are pointers to higher level
1631   IDs, or NULL.  LANGUAGE is a pointer to the current language.
1632   LEVEL is the level in the tree.  */
1633
1634static void
1635write_rc_subdir (e, re, type, name, language, level)
1636     FILE *e;
1637     const struct res_entry *re;
1638     const struct res_id *type;
1639     const struct res_id *name;
1640     int *language;
1641     int level;
1642{
1643  fprintf (e, "\n");
1644  switch (level)
1645    {
1646    case 1:
1647      fprintf (e, "// Type: ");
1648      if (re->id.named)
1649	res_id_print (e, re->id, 1);
1650      else
1651	{
1652	  const char *s;
1653
1654	  switch (re->id.u.id)
1655	    {
1656	    case RT_CURSOR: s = "cursor"; break;
1657	    case RT_BITMAP: s = "bitmap"; break;
1658	    case RT_ICON: s = "icon"; break;
1659	    case RT_MENU: s = "menu"; break;
1660	    case RT_DIALOG: s = "dialog"; break;
1661	    case RT_STRING: s = "stringtable"; break;
1662	    case RT_FONTDIR: s = "fontdir"; break;
1663	    case RT_FONT: s = "font"; break;
1664	    case RT_ACCELERATOR: s = "accelerators"; break;
1665	    case RT_RCDATA: s = "rcdata"; break;
1666	    case RT_MESSAGETABLE: s = "messagetable"; break;
1667	    case RT_GROUP_CURSOR: s = "group cursor"; break;
1668	    case RT_GROUP_ICON: s = "group icon"; break;
1669	    case RT_VERSION: s = "version"; break;
1670	    case RT_DLGINCLUDE: s = "dlginclude"; break;
1671	    case RT_PLUGPLAY: s = "plugplay"; break;
1672	    case RT_VXD: s = "vxd"; break;
1673	    case RT_ANICURSOR: s = "anicursor"; break;
1674	    case RT_ANIICON: s = "aniicon"; break;
1675	    default: s = NULL; break;
1676	    }
1677
1678	  if (s != NULL)
1679	    fprintf (e, "%s", s);
1680	  else
1681	    res_id_print (e, re->id, 1);
1682	}
1683      fprintf (e, "\n");
1684      break;
1685
1686    case 2:
1687      fprintf (e, "// Name: ");
1688      res_id_print (e, re->id, 1);
1689      fprintf (e, "\n");
1690      break;
1691
1692    case 3:
1693      fprintf (e, "// Language: ");
1694      res_id_print (e, re->id, 1);
1695      fprintf (e, "\n");
1696      break;
1697
1698    default:
1699      fprintf (e, "// Level %d: ", level);
1700      res_id_print (e, re->id, 1);
1701      fprintf (e, "\n");
1702    }
1703
1704  write_rc_directory (e, re->u.dir, type, name, language, level + 1);
1705}
1706
1707/* Write out a single resource.  E is the file to write to.  TYPE is a
1708   pointer to the type of the resource.  NAME is a pointer to the name
1709   of the resource; it will be NULL if there is a level mismatch.  RES
1710   is the resource data.  LANGUAGE is a pointer to the current
1711   language.  */
1712
1713static void
1714write_rc_resource (e, type, name, res, language)
1715     FILE *e;
1716     const struct res_id *type;
1717     const struct res_id *name;
1718     const struct res_resource *res;
1719     int *language;
1720{
1721  const char *s;
1722  int rt;
1723  int menuex = 0;
1724
1725  fprintf (e, "\n");
1726
1727  switch (res->type)
1728    {
1729    default:
1730      abort ();
1731
1732    case RES_TYPE_ACCELERATOR:
1733      s = "ACCELERATOR";
1734      rt = RT_ACCELERATOR;
1735      break;
1736
1737    case RES_TYPE_BITMAP:
1738      s = "BITMAP";
1739      rt = RT_BITMAP;
1740      break;
1741
1742    case RES_TYPE_CURSOR:
1743      s = "CURSOR";
1744      rt = RT_CURSOR;
1745      break;
1746
1747    case RES_TYPE_GROUP_CURSOR:
1748      s = "GROUP_CURSOR";
1749      rt = RT_GROUP_CURSOR;
1750      break;
1751
1752    case RES_TYPE_DIALOG:
1753      if (extended_dialog (res->u.dialog))
1754	s = "DIALOGEX";
1755      else
1756	s = "DIALOG";
1757      rt = RT_DIALOG;
1758      break;
1759
1760    case RES_TYPE_FONT:
1761      s = "FONT";
1762      rt = RT_FONT;
1763      break;
1764
1765    case RES_TYPE_FONTDIR:
1766      s = "FONTDIR";
1767      rt = RT_FONTDIR;
1768      break;
1769
1770    case RES_TYPE_ICON:
1771      s = "ICON";
1772      rt = RT_ICON;
1773      break;
1774
1775    case RES_TYPE_GROUP_ICON:
1776      s = "GROUP_ICON";
1777      rt = RT_GROUP_ICON;
1778      break;
1779
1780    case RES_TYPE_MENU:
1781      if (extended_menu (res->u.menu))
1782	{
1783	  s = "MENUEX";
1784	  menuex = 1;
1785	}
1786      else
1787	{
1788	  s = "MENU";
1789	  menuex = 0;
1790	}
1791      rt = RT_MENU;
1792      break;
1793
1794    case RES_TYPE_MESSAGETABLE:
1795      s = "MESSAGETABLE";
1796      rt = RT_MESSAGETABLE;
1797      break;
1798
1799    case RES_TYPE_RCDATA:
1800      s = "RCDATA";
1801      rt = RT_RCDATA;
1802      break;
1803
1804    case RES_TYPE_STRINGTABLE:
1805      s = "STRINGTABLE";
1806      rt = RT_STRING;
1807      break;
1808
1809    case RES_TYPE_USERDATA:
1810      s = NULL;
1811      rt = 0;
1812      break;
1813
1814    case RES_TYPE_VERSIONINFO:
1815      s = "VERSIONINFO";
1816      rt = RT_VERSION;
1817      break;
1818    }
1819
1820  if (rt != 0
1821      && type != NULL
1822      && (type->named || type->u.id != (unsigned long) rt))
1823    {
1824      fprintf (e, "// Unexpected resource type mismatch: ");
1825      res_id_print (e, *type, 1);
1826      fprintf (e, " != %d", rt);
1827    }
1828
1829  if (res->coff_info.codepage != 0)
1830    fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
1831  if (res->coff_info.reserved != 0)
1832    fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
1833
1834  if (name != NULL)
1835    res_id_print (e, *name, 0);
1836  else
1837    fprintf (e, "??Unknown-Name??");
1838
1839  fprintf (e, " ");
1840  if (s != NULL)
1841    fprintf (e, "%s", s);
1842  else if (type != NULL)
1843    res_id_print (e, *type, 0);
1844  else
1845    fprintf (e, "??Unknown-Type??");
1846
1847  if (res->res_info.memflags != 0)
1848    {
1849      if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
1850	fprintf (e, " MOVEABLE");
1851      if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
1852	fprintf (e, " PURE");
1853      if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
1854	fprintf (e, " PRELOAD");
1855      if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
1856	fprintf (e, " DISCARDABLE");
1857    }
1858
1859  if (res->type == RES_TYPE_DIALOG)
1860    {
1861      fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
1862	       res->u.dialog->width, res->u.dialog->height);
1863      if (res->u.dialog->ex != NULL
1864	  && res->u.dialog->ex->help != 0)
1865	fprintf (e, ", %lu", res->u.dialog->ex->help);
1866    }
1867
1868  fprintf (e, "\n");
1869
1870  if ((res->res_info.language != 0 && res->res_info.language != *language)
1871      || res->res_info.characteristics != 0
1872      || res->res_info.version != 0)
1873    {
1874      int modifiers;
1875
1876      switch (res->type)
1877	{
1878	case RES_TYPE_ACCELERATOR:
1879	case RES_TYPE_DIALOG:
1880	case RES_TYPE_MENU:
1881	case RES_TYPE_RCDATA:
1882	case RES_TYPE_STRINGTABLE:
1883	  modifiers = 1;
1884	  break;
1885
1886	default:
1887	  modifiers = 0;
1888	  break;
1889	}
1890
1891      if (res->res_info.language != 0 && res->res_info.language != *language)
1892	fprintf (e, "%sLANGUAGE %d, %d\n",
1893		 modifiers ? "// " : "",
1894		 res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
1895		 (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
1896      if (res->res_info.characteristics != 0)
1897	fprintf (e, "%sCHARACTERISTICS %lu\n",
1898		 modifiers ? "// " : "",
1899		 res->res_info.characteristics);
1900      if (res->res_info.version != 0)
1901	fprintf (e, "%sVERSION %lu\n",
1902		 modifiers ? "// " : "",
1903		 res->res_info.version);
1904    }
1905
1906  switch (res->type)
1907    {
1908    default:
1909      abort ();
1910
1911    case RES_TYPE_ACCELERATOR:
1912      write_rc_accelerators (e, res->u.acc);
1913      break;
1914
1915    case RES_TYPE_CURSOR:
1916      write_rc_cursor (e, res->u.cursor);
1917      break;
1918
1919    case RES_TYPE_GROUP_CURSOR:
1920      write_rc_group_cursor (e, res->u.group_cursor);
1921      break;
1922
1923    case RES_TYPE_DIALOG:
1924      write_rc_dialog (e, res->u.dialog);
1925      break;
1926
1927    case RES_TYPE_FONTDIR:
1928      write_rc_fontdir (e, res->u.fontdir);
1929      break;
1930
1931    case RES_TYPE_GROUP_ICON:
1932      write_rc_group_icon (e, res->u.group_icon);
1933      break;
1934
1935    case RES_TYPE_MENU:
1936      write_rc_menu (e, res->u.menu, menuex);
1937      break;
1938
1939    case RES_TYPE_RCDATA:
1940      write_rc_rcdata (e, res->u.rcdata, 0);
1941      break;
1942
1943    case RES_TYPE_STRINGTABLE:
1944      write_rc_stringtable (e, name, res->u.stringtable);
1945      break;
1946
1947    case RES_TYPE_USERDATA:
1948      write_rc_rcdata (e, res->u.userdata, 0);
1949      break;
1950
1951    case RES_TYPE_VERSIONINFO:
1952      write_rc_versioninfo (e, res->u.versioninfo);
1953      break;
1954
1955    case RES_TYPE_BITMAP:
1956    case RES_TYPE_FONT:
1957    case RES_TYPE_ICON:
1958    case RES_TYPE_MESSAGETABLE:
1959      write_rc_filedata (e, res->u.data.length, res->u.data.data);
1960      break;
1961    }
1962}
1963
1964/* Write out accelerator information.  */
1965
1966static void
1967write_rc_accelerators (e, accelerators)
1968     FILE *e;
1969     const struct accelerator *accelerators;
1970{
1971  const struct accelerator *acc;
1972
1973  fprintf (e, "BEGIN\n");
1974  for (acc = accelerators; acc != NULL; acc = acc->next)
1975    {
1976      int printable;
1977
1978      fprintf (e, "  ");
1979
1980      if ((acc->key & 0x7f) == acc->key
1981	  && ISPRINT (acc->key)
1982	  && (acc->flags & ACC_VIRTKEY) == 0)
1983	{
1984	  fprintf (e, "\"%c\"", acc->key);
1985	  printable = 1;
1986	}
1987      else
1988	{
1989	  fprintf (e, "%d", acc->key);
1990	  printable = 0;
1991	}
1992
1993      fprintf (e, ", %d", acc->id);
1994
1995      if (! printable)
1996	{
1997	  if ((acc->flags & ACC_VIRTKEY) != 0)
1998	    fprintf (e, ", VIRTKEY");
1999	  else
2000	    fprintf (e, ", ASCII");
2001	}
2002
2003      if ((acc->flags & ACC_SHIFT) != 0)
2004	fprintf (e, ", SHIFT");
2005      if ((acc->flags & ACC_CONTROL) != 0)
2006	fprintf (e, ", CONTROL");
2007      if ((acc->flags & ACC_ALT) != 0)
2008	fprintf (e, ", ALT");
2009
2010      fprintf (e, "\n");
2011    }
2012
2013  fprintf (e, "END\n");
2014}
2015
2016/* Write out cursor information.  This would normally be in a separate
2017   file, which the rc file would include.  */
2018
2019static void
2020write_rc_cursor (e, cursor)
2021     FILE *e;
2022     const struct cursor *cursor;
2023{
2024  fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
2025	   cursor->yhotspot);
2026  write_rc_filedata (e, cursor->length, cursor->data);
2027}
2028
2029/* Write out group cursor data.  This would normally be built from the
2030   cursor data.  */
2031
2032static void
2033write_rc_group_cursor (e, group_cursor)
2034     FILE *e;
2035     const struct group_cursor *group_cursor;
2036{
2037  const struct group_cursor *gc;
2038
2039  for (gc = group_cursor; gc != NULL; gc = gc->next)
2040    {
2041      fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
2042	     gc->width, gc->height, gc->planes, gc->bits);
2043      fprintf (e, "// data bytes: %lu; index: %d\n",
2044	       gc->bytes, gc->index);
2045    }
2046}
2047
2048/* Write dialog data.  */
2049
2050static void
2051write_rc_dialog (e, dialog)
2052     FILE *e;
2053     const struct dialog *dialog;
2054{
2055  const struct dialog_control *control;
2056
2057  fprintf (e, "STYLE 0x%lx\n", dialog->style);
2058
2059  if (dialog->exstyle != 0)
2060    fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
2061
2062  if ((dialog->class.named && dialog->class.u.n.length > 0)
2063      || dialog->class.u.id != 0)
2064    {
2065      fprintf (e, "CLASS ");
2066      res_id_print (e, dialog->class, 1);
2067      fprintf (e, "\n");
2068    }
2069
2070  if (dialog->caption != NULL)
2071    {
2072      fprintf (e, "CAPTION \"");
2073      unicode_print (e, dialog->caption, -1);
2074      fprintf (e, "\"\n");
2075    }
2076
2077  if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2078      || dialog->menu.u.id != 0)
2079    {
2080      fprintf (e, "MENU ");
2081      res_id_print (e, dialog->menu, 0);
2082      fprintf (e, "\n");
2083    }
2084
2085  if (dialog->font != NULL)
2086    {
2087      fprintf (e, "FONT %d, \"", dialog->pointsize);
2088      unicode_print (e, dialog->font, -1);
2089      fprintf (e, "\"");
2090      if (dialog->ex != NULL
2091	  && (dialog->ex->weight != 0
2092	      || dialog->ex->italic != 0
2093	      || dialog->ex->charset != 1))
2094	fprintf (e, ", %d, %d, %d",
2095		 dialog->ex->weight, dialog->ex->italic, dialog->ex->charset);
2096      fprintf (e, "\n");
2097    }
2098
2099  fprintf (e, "BEGIN\n");
2100
2101  for (control = dialog->controls; control != NULL; control = control->next)
2102    write_rc_dialog_control (e, control);
2103
2104  fprintf (e, "END\n");
2105}
2106
2107/* For each predefined control keyword, this table provides the class
2108   and the style.  */
2109
2110struct control_info
2111{
2112  const char *name;
2113  unsigned short class;
2114  unsigned long style;
2115};
2116
2117static const struct control_info control_info[] =
2118{
2119  { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2120  { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2121  { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2122  { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2123  { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2124  { "CTEXT", CTL_STATIC, SS_CENTER },
2125  { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2126  { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2127  { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2128  { "ICON", CTL_STATIC, SS_ICON },
2129  { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2130  { "LTEXT", CTL_STATIC, SS_LEFT },
2131  { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2132  { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2133  { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2134  { "RTEXT", CTL_STATIC, SS_RIGHT },
2135  { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2136  { "STATE3", CTL_BUTTON, BS_3STATE },
2137  /* It's important that USERBUTTON come after all the other button
2138     types, so that it won't be matched too early.  */
2139  { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2140  { NULL, 0, 0 }
2141};
2142
2143/* Write a dialog control.  */
2144
2145static void
2146write_rc_dialog_control (e, control)
2147     FILE *e;
2148     const struct dialog_control *control;
2149{
2150  const struct control_info *ci;
2151
2152  fprintf (e, "  ");
2153
2154  if (control->class.named)
2155    ci = NULL;
2156  else
2157    {
2158      for (ci = control_info; ci->name != NULL; ++ci)
2159	if (ci->class == control->class.u.id
2160	    && (ci->style == (unsigned long) -1
2161		|| ci->style == (control->style & 0xff)))
2162	  break;
2163    }
2164  if (ci == NULL)
2165    fprintf (e, "CONTROL");
2166  else if (ci->name != NULL)
2167    fprintf (e, "%s", ci->name);
2168  else
2169    fprintf (e, "CONTROL");
2170
2171  if (control->text.named || control->text.u.id != 0)
2172    {
2173      fprintf (e, " ");
2174      res_id_print (e, control->text, 1);
2175      fprintf (e, ",");
2176    }
2177
2178  fprintf (e, " %d, ", control->id);
2179
2180  if (ci == NULL)
2181    {
2182      if (control->class.named)
2183	fprintf (e, "\"");
2184      res_id_print (e, control->class, 0);
2185      if (control->class.named)
2186	fprintf (e, "\"");
2187      fprintf (e, ", 0x%lx, ", control->style);
2188    }
2189
2190  fprintf (e, "%d, %d", control->x, control->y);
2191
2192  if (control->style != SS_ICON
2193      || control->exstyle != 0
2194      || control->width != 0
2195      || control->height != 0
2196      || control->help != 0)
2197    {
2198      fprintf (e, ", %d, %d", control->width, control->height);
2199
2200      /* FIXME: We don't need to print the style if it is the default.
2201	 More importantly, in certain cases we actually need to turn
2202	 off parts of the forced style, by using NOT.  */
2203      fprintf (e, ", 0x%lx", control->style);
2204
2205      if (control->exstyle != 0 || control->help != 0)
2206	fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
2207    }
2208
2209  fprintf (e, "\n");
2210
2211  if (control->data != NULL)
2212    write_rc_rcdata (e, control->data, 2);
2213}
2214
2215/* Write out font directory data.  This would normally be built from
2216   the font data.  */
2217
2218static void
2219write_rc_fontdir (e, fontdir)
2220     FILE *e;
2221     const struct fontdir *fontdir;
2222{
2223  const struct fontdir *fc;
2224
2225  for (fc = fontdir; fc != NULL; fc = fc->next)
2226    {
2227      fprintf (e, "// Font index: %d\n", fc->index);
2228      write_rc_filedata (e, fc->length, fc->data);
2229    }
2230}
2231
2232/* Write out group icon data.  This would normally be built from the
2233   icon data.  */
2234
2235static void
2236write_rc_group_icon (e, group_icon)
2237     FILE *e;
2238     const struct group_icon *group_icon;
2239{
2240  const struct group_icon *gi;
2241
2242  for (gi = group_icon; gi != NULL; gi = gi->next)
2243    {
2244      fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
2245	       gi->width, gi->height, gi->colors, gi->planes, gi->bits);
2246      fprintf (e, "// data bytes: %lu; index: %d\n",
2247	       gi->bytes, gi->index);
2248    }
2249}
2250
2251/* Write out a menu resource.  */
2252
2253static void
2254write_rc_menu (e, menu, menuex)
2255     FILE *e;
2256     const struct menu *menu;
2257     int menuex;
2258{
2259  if (menu->help != 0)
2260    fprintf (e, "// Help ID: %lu\n", menu->help);
2261  write_rc_menuitems (e, menu->items, menuex, 0);
2262}
2263
2264/* Write out menuitems.  */
2265
2266static void
2267write_rc_menuitems (e, menuitems, menuex, ind)
2268     FILE *e;
2269     const struct menuitem *menuitems;
2270     int menuex;
2271     int ind;
2272{
2273  const struct menuitem *mi;
2274
2275  indent (e, ind);
2276  fprintf (e, "BEGIN\n");
2277
2278  for (mi = menuitems; mi != NULL; mi = mi->next)
2279    {
2280      indent (e, ind + 2);
2281
2282      if (mi->popup == NULL)
2283	fprintf (e, "MENUITEM");
2284      else
2285	fprintf (e, "POPUP");
2286
2287      if (! menuex
2288	  && mi->popup == NULL
2289	  && mi->text == NULL
2290	  && mi->type == 0
2291	  && mi->id == 0)
2292	{
2293	  fprintf (e, " SEPARATOR\n");
2294	  continue;
2295	}
2296
2297      if (mi->text == NULL)
2298	fprintf (e, " \"\"");
2299      else
2300	{
2301	  fprintf (e, " \"");
2302	  unicode_print (e, mi->text, -1);
2303	  fprintf (e, "\"");
2304	}
2305
2306      if (! menuex)
2307	{
2308	  if (mi->popup == NULL)
2309	    fprintf (e, ", %d", mi->id);
2310
2311	  if ((mi->type & MENUITEM_CHECKED) != 0)
2312	    fprintf (e, ", CHECKED");
2313	  if ((mi->type & MENUITEM_GRAYED) != 0)
2314	    fprintf (e, ", GRAYED");
2315	  if ((mi->type & MENUITEM_HELP) != 0)
2316	    fprintf (e, ", HELP");
2317	  if ((mi->type & MENUITEM_INACTIVE) != 0)
2318	    fprintf (e, ", INACTIVE");
2319	  if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2320	    fprintf (e, ", MENUBARBREAK");
2321	  if ((mi->type & MENUITEM_MENUBREAK) != 0)
2322	    fprintf (e, ", MENUBREAK");
2323	}
2324      else
2325	{
2326	  if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2327	    {
2328	      fprintf (e, ", %d", mi->id);
2329	      if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2330		{
2331		  fprintf (e, ", %lu", mi->type);
2332		  if (mi->state != 0 || mi->help != 0)
2333		    {
2334		      fprintf (e, ", %lu", mi->state);
2335		      if (mi->help != 0)
2336			fprintf (e, ", %lu", mi->help);
2337		    }
2338		}
2339	    }
2340	}
2341
2342      fprintf (e, "\n");
2343
2344      if (mi->popup != NULL)
2345	write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2346    }
2347
2348  indent (e, ind);
2349  fprintf (e, "END\n");
2350}
2351
2352/* Write out an rcdata resource.  This is also used for other types of
2353   resources that need to print arbitrary data.  */
2354
2355static void
2356write_rc_rcdata (e, rcdata, ind)
2357     FILE *e;
2358     const struct rcdata_item *rcdata;
2359     int ind;
2360{
2361  const struct rcdata_item *ri;
2362
2363  indent (e, ind);
2364  fprintf (e, "BEGIN\n");
2365
2366  for (ri = rcdata; ri != NULL; ri = ri->next)
2367    {
2368      if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
2369	continue;
2370
2371      indent (e, ind + 2);
2372
2373      switch (ri->type)
2374	{
2375	default:
2376	  abort ();
2377
2378	case RCDATA_WORD:
2379	  fprintf (e, "%d", ri->u.word);
2380	  break;
2381
2382	case RCDATA_DWORD:
2383	  fprintf (e, "%luL", ri->u.dword);
2384	  break;
2385
2386	case RCDATA_STRING:
2387	  {
2388	    const char *s;
2389	    unsigned long i;
2390
2391	    fprintf (e, "\"");
2392	    s = ri->u.string.s;
2393	    for (i = 0; i < ri->u.string.length; i++)
2394	      {
2395		if (ISPRINT (*s))
2396		  putc (*s, e);
2397		else
2398		  fprintf (e, "\\%03o", *s);
2399	      }
2400	    fprintf (e, "\"");
2401	    break;
2402	  }
2403
2404	case RCDATA_WSTRING:
2405	  fprintf (e, "L\"");
2406	  unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
2407	  fprintf (e, "\"");
2408	  break;
2409
2410	case RCDATA_BUFFER:
2411	  {
2412	    unsigned long i;
2413	    int first;
2414
2415	    /* Assume little endian data.  */
2416
2417	    first = 1;
2418	    for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
2419	      {
2420		unsigned long l;
2421		int j;
2422
2423		if (! first)
2424		  indent (e, ind + 2);
2425		l = ((((((ri->u.buffer.data[i + 3] << 8)
2426			 | ri->u.buffer.data[i + 2]) << 8)
2427		       | ri->u.buffer.data[i + 1]) << 8)
2428		     | ri->u.buffer.data[i]);
2429		fprintf (e, "%luL", l);
2430		if (i + 4 < ri->u.buffer.length || ri->next != NULL)
2431		  fprintf (e, ",");
2432		for (j = 0; j < 4; ++j)
2433		  if (! ISPRINT (ri->u.buffer.data[i + j])
2434		      && ri->u.buffer.data[i + j] != 0)
2435		    break;
2436		if (j >= 4)
2437		  {
2438		    fprintf (e, "\t// ");
2439		    for (j = 0; j < 4; ++j)
2440		      {
2441			if (! ISPRINT (ri->u.buffer.data[i + j]))
2442			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2443			else
2444			  {
2445			    if (ri->u.buffer.data[i + j] == '\\')
2446			      fprintf (e, "\\");
2447			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
2448			  }
2449		      }
2450		  }
2451		fprintf (e, "\n");
2452		first = 0;
2453	      }
2454
2455	    if (i + 1 < ri->u.buffer.length)
2456	      {
2457		int s;
2458		int j;
2459
2460		if (! first)
2461		  indent (e, ind + 2);
2462		s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
2463		fprintf (e, "%d", s);
2464		if (i + 2 < ri->u.buffer.length || ri->next != NULL)
2465		  fprintf (e, ",");
2466		for (j = 0; j < 2; ++j)
2467		  if (! ISPRINT (ri->u.buffer.data[i + j])
2468		      && ri->u.buffer.data[i + j] != 0)
2469		    break;
2470		if (j >= 2)
2471		  {
2472		    fprintf (e, "\t// ");
2473		    for (j = 0; j < 2; ++j)
2474		      {
2475			if (! ISPRINT (ri->u.buffer.data[i + j]))
2476			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2477			else
2478			  {
2479			    if (ri->u.buffer.data[i + j] == '\\')
2480			      fprintf (e, "\\");
2481			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
2482			  }
2483		      }
2484		  }
2485		fprintf (e, "\n");
2486		i += 2;
2487		first = 0;
2488	      }
2489
2490	    if (i < ri->u.buffer.length)
2491	      {
2492		if (! first)
2493		  indent (e, ind + 2);
2494		if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
2495		    && ISPRINT (ri->u.buffer.data[i]))
2496		  fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
2497		else
2498		  fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
2499		if (ri->next != NULL)
2500		  fprintf (e, ",");
2501		fprintf (e, "\n");
2502		first = 0;
2503	      }
2504
2505	    break;
2506	  }
2507	}
2508
2509      if (ri->type != RCDATA_BUFFER)
2510	{
2511	  if (ri->next != NULL)
2512	    fprintf (e, ",");
2513	  fprintf (e, "\n");
2514	}
2515    }
2516
2517  indent (e, ind);
2518  fprintf (e, "END\n");
2519}
2520
2521/* Write out a stringtable resource.  */
2522
2523static void
2524write_rc_stringtable (e, name, stringtable)
2525     FILE *e;
2526     const struct res_id *name;
2527     const struct stringtable *stringtable;
2528{
2529  unsigned long offset;
2530  int i;
2531
2532  if (name != NULL && ! name->named)
2533    offset = (name->u.id - 1) << 4;
2534  else
2535    {
2536      fprintf (e, "// %s string table name\n",
2537	       name == NULL ? "Missing" : "Invalid");
2538      offset = 0;
2539    }
2540
2541  fprintf (e, "BEGIN\n");
2542
2543  for (i = 0; i < 16; i++)
2544    {
2545      if (stringtable->strings[i].length != 0)
2546	{
2547	  fprintf (e, "  %lu, \"", offset + i);
2548	  unicode_print (e, stringtable->strings[i].string,
2549			 stringtable->strings[i].length);
2550	  fprintf (e, "\"\n");
2551	}
2552    }
2553
2554  fprintf (e, "END\n");
2555}
2556
2557/* Write out a versioninfo resource.  */
2558
2559static void
2560write_rc_versioninfo (e, versioninfo)
2561     FILE *e;
2562     const struct versioninfo *versioninfo;
2563{
2564  const struct fixed_versioninfo *f;
2565  const struct ver_info *vi;
2566
2567  f = versioninfo->fixed;
2568  if (f->file_version_ms != 0 || f->file_version_ls != 0)
2569    fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
2570	     (f->file_version_ms >> 16) & 0xffff,
2571	     f->file_version_ms & 0xffff,
2572	     (f->file_version_ls >> 16) & 0xffff,
2573	     f->file_version_ls & 0xffff);
2574  if (f->product_version_ms != 0 || f->product_version_ls != 0)
2575    fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
2576	     (f->product_version_ms >> 16) & 0xffff,
2577	     f->product_version_ms & 0xffff,
2578	     (f->product_version_ls >> 16) & 0xffff,
2579	     f->product_version_ls & 0xffff);
2580  if (f->file_flags_mask != 0)
2581    fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
2582  if (f->file_flags != 0)
2583    fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
2584  if (f->file_os != 0)
2585    fprintf (e, " FILEOS 0x%lx\n", f->file_os);
2586  if (f->file_type != 0)
2587    fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
2588  if (f->file_subtype != 0)
2589    fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
2590  if (f->file_date_ms != 0 || f->file_date_ls != 0)
2591    fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
2592
2593  fprintf (e, "BEGIN\n");
2594
2595  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2596    {
2597      switch (vi->type)
2598	{
2599	case VERINFO_STRING:
2600	  {
2601	    const struct ver_stringinfo *vs;
2602
2603	    fprintf (e, "  BLOCK \"StringFileInfo\"\n");
2604	    fprintf (e, "  BEGIN\n");
2605	    fprintf (e, "    BLOCK \"");
2606	    unicode_print (e, vi->u.string.language, -1);
2607	    fprintf (e, "\"\n");
2608	    fprintf (e, "    BEGIN\n");
2609
2610	    for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2611	      {
2612		fprintf (e, "      VALUE \"");
2613		unicode_print (e, vs->key, -1);
2614		fprintf (e, "\", \"");
2615		unicode_print (e, vs->value, -1);
2616		fprintf (e, "\"\n");
2617	      }
2618
2619	    fprintf (e, "    END\n");
2620	    fprintf (e, "  END\n");
2621	    break;
2622	  }
2623
2624	case VERINFO_VAR:
2625	  {
2626	    const struct ver_varinfo *vv;
2627
2628	    fprintf (e, "  BLOCK \"VarFileInfo\"\n");
2629	    fprintf (e, "  BEGIN\n");
2630	    fprintf (e, "    VALUE \"");
2631	    unicode_print (e, vi->u.var.key, -1);
2632	    fprintf (e, "\"");
2633
2634	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2635	      fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
2636		       vv->charset);
2637
2638	    fprintf (e, "\n  END\n");
2639
2640	    break;
2641	  }
2642	}
2643    }
2644
2645  fprintf (e, "END\n");
2646}
2647
2648/* Write out data which would normally be read from a file.  */
2649
2650static void
2651write_rc_filedata (e, length, data)
2652     FILE *e;
2653     unsigned long length;
2654     const unsigned char *data;
2655{
2656  unsigned long i;
2657
2658  for (i = 0; i + 15 < length; i += 16)
2659    {
2660      fprintf (e, "// %4lx: ", i);
2661      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
2662	       data[i + 0], data[i + 1], data[i + 2], data[i + 3],
2663	       data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
2664      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2665	       data[i +  8], data[i +  9], data[i + 10], data[i + 11],
2666	       data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
2667    }
2668
2669  if (i < length)
2670    {
2671      fprintf (e, "// %4lx:", i);
2672      while (i < length)
2673	{
2674	  fprintf (e, " %02x", data[i]);
2675	  ++i;
2676	}
2677      fprintf (e, "\n");
2678    }
2679}
2680