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