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