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