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