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