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