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