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