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