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