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