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