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