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