Fix overlooked sublang shift bug.
[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 || dialog->ex->italic != 0))
2091         fprintf (e, ", %d, %d", dialog->ex->weight, dialog->ex->italic);
2092       fprintf (e, "\n");
2093     }
2094
2095   fprintf (e, "BEGIN\n");
2096
2097   for (control = dialog->controls; control != NULL; control = control->next)
2098     write_rc_dialog_control (e, control);
2099
2100   fprintf (e, "END\n");
2101 }
2102
2103 /* For each predefined control keyword, this table provides the class
2104    and the style.  */
2105
2106 struct control_info
2107 {
2108   const char *name;
2109   unsigned short class;
2110   unsigned long style;
2111 };
2112
2113 static const struct control_info control_info[] =
2114 {
2115   { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2116   { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2117   { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2118   { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2119   { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2120   { "CTEXT", CTL_STATIC, SS_CENTER },
2121   { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2122   { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2123   { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2124   { "ICON", CTL_STATIC, SS_ICON },
2125   { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2126   { "LTEXT", CTL_STATIC, SS_LEFT },
2127   { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2128   { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2129   { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2130   { "RTEXT", CTL_STATIC, SS_RIGHT },
2131   { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2132   { "STATE3", CTL_BUTTON, BS_3STATE },
2133   /* It's important that USERBUTTON come after all the other button
2134      types, so that it won't be matched too early.  */
2135   { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2136   { NULL, 0, 0 }
2137 };
2138
2139 /* Write a dialog control.  */
2140
2141 static void
2142 write_rc_dialog_control (e, control)
2143      FILE *e;
2144      const struct dialog_control *control;
2145 {
2146   const struct control_info *ci;
2147
2148   fprintf (e, "  ");
2149
2150   if (control->class.named)
2151     ci = NULL;
2152   else
2153     {
2154       for (ci = control_info; ci->name != NULL; ++ci)
2155         if (ci->class == control->class.u.id
2156             && (ci->style == (unsigned long) -1
2157                 || ci->style == (control->style & 0xff)))
2158           break;
2159     }
2160   if (ci == NULL)
2161     fprintf (e, "CONTROL");
2162   else if (ci->name != NULL)
2163     fprintf (e, "%s", ci->name);
2164   else
2165     fprintf (e, "CONTROL");
2166   
2167   if (control->text.named || control->text.u.id != 0)
2168     {
2169       fprintf (e, " ");
2170       res_id_print (e, control->text, 1);
2171       fprintf (e, ",");
2172     }
2173
2174   fprintf (e, " %d, ", control->id);
2175
2176   if (ci == NULL)
2177     {
2178       if (control->class.named)
2179         fprintf (e, "\"");
2180       res_id_print (e, control->class, 0);
2181       if (control->class.named)
2182         fprintf (e, "\"");
2183       fprintf (e, ", 0x%lx, ", control->style);
2184     }
2185
2186   fprintf (e, "%d, %d", control->x, control->y);
2187
2188   if (control->style != SS_ICON
2189       || control->exstyle != 0
2190       || control->width != 0
2191       || control->height != 0
2192       || control->help != 0)
2193     {
2194       fprintf (e, ", %d, %d", control->width, control->height);
2195
2196       /* FIXME: We don't need to print the style if it is the default.
2197          More importantly, in certain cases we actually need to turn
2198          off parts of the forced style, by using NOT.  */
2199       fprintf (e, ", 0x%lx", control->style);
2200
2201       if (control->exstyle != 0 || control->help != 0)
2202         fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
2203     }
2204
2205   fprintf (e, "\n");
2206
2207   if (control->data != NULL)
2208     write_rc_rcdata (e, control->data, 2);
2209 }
2210
2211 /* Write out font directory data.  This would normally be built from
2212    the font data.  */
2213
2214 static void
2215 write_rc_fontdir (e, fontdir)
2216      FILE *e;
2217      const struct fontdir *fontdir;
2218 {
2219   const struct fontdir *fc;
2220
2221   for (fc = fontdir; fc != NULL; fc = fc->next)
2222     {
2223       fprintf (e, "// Font index: %d\n", fc->index);
2224       write_rc_filedata (e, fc->length, fc->data);
2225     }
2226 }
2227
2228 /* Write out group icon data.  This would normally be built from the
2229    icon data.  */
2230
2231 static void
2232 write_rc_group_icon (e, group_icon)
2233      FILE *e;
2234      const struct group_icon *group_icon;
2235 {
2236   const struct group_icon *gi;
2237
2238   for (gi = group_icon; gi != NULL; gi = gi->next)
2239     {
2240       fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
2241                gi->width, gi->height, gi->colors, gi->planes, gi->bits);
2242       fprintf (e, "// data bytes: %lu; index: %d\n",
2243                gi->bytes, gi->index);
2244     }
2245 }
2246
2247 /* Write out a menu resource.  */
2248
2249 static void
2250 write_rc_menu (e, menu, menuex)
2251      FILE *e;
2252      const struct menu *menu;
2253      int menuex;
2254 {
2255   if (menu->help != 0)
2256     fprintf (e, "// Help ID: %lu\n", menu->help);
2257   write_rc_menuitems (e, menu->items, menuex, 0);
2258 }
2259
2260 /* Write out menuitems.  */
2261
2262 static void
2263 write_rc_menuitems (e, menuitems, menuex, ind)
2264      FILE *e;
2265      const struct menuitem *menuitems;
2266      int menuex;
2267      int ind;
2268 {
2269   const struct menuitem *mi;
2270
2271   indent (e, ind);
2272   fprintf (e, "BEGIN\n");
2273
2274   for (mi = menuitems; mi != NULL; mi = mi->next)
2275     {
2276       indent (e, ind + 2);
2277
2278       if (mi->popup == NULL)
2279         fprintf (e, "MENUITEM");
2280       else
2281         fprintf (e, "POPUP");
2282
2283       if (! menuex
2284           && mi->popup == NULL
2285           && mi->text == NULL
2286           && mi->type == 0
2287           && mi->id == 0)
2288         {
2289           fprintf (e, " SEPARATOR\n");
2290           continue;
2291         }
2292
2293       if (mi->text == NULL)
2294         fprintf (e, " \"\"");
2295       else
2296         {
2297           fprintf (e, " \"");
2298           unicode_print (e, mi->text, -1);
2299           fprintf (e, "\"");
2300         }
2301
2302       if (! menuex)
2303         {
2304           if (mi->popup == NULL)
2305             fprintf (e, ", %d", mi->id);
2306
2307           if ((mi->type & MENUITEM_CHECKED) != 0)
2308             fprintf (e, ", CHECKED");
2309           if ((mi->type & MENUITEM_GRAYED) != 0)
2310             fprintf (e, ", GRAYED");
2311           if ((mi->type & MENUITEM_HELP) != 0)
2312             fprintf (e, ", HELP");
2313           if ((mi->type & MENUITEM_INACTIVE) != 0)
2314             fprintf (e, ", INACTIVE");
2315           if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2316             fprintf (e, ", MENUBARBREAK");
2317           if ((mi->type & MENUITEM_MENUBREAK) != 0)
2318             fprintf (e, ", MENUBREAK");
2319         }
2320       else
2321         {
2322           if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2323             {
2324               fprintf (e, ", %d", mi->id);
2325               if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2326                 {
2327                   fprintf (e, ", %lu", mi->type);
2328                   if (mi->state != 0 || mi->help != 0)
2329                     {
2330                       fprintf (e, ", %lu", mi->state);
2331                       if (mi->help != 0)
2332                         fprintf (e, ", %lu", mi->help);
2333                     }
2334                 }
2335             }
2336         }
2337
2338       fprintf (e, "\n");
2339
2340       if (mi->popup != NULL)
2341         write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2342     }
2343
2344   indent (e, ind);
2345   fprintf (e, "END\n");
2346 }
2347
2348 /* Write out an rcdata resource.  This is also used for other types of
2349    resources that need to print arbitrary data.  */
2350
2351 static void
2352 write_rc_rcdata (e, rcdata, ind)
2353      FILE *e;
2354      const struct rcdata_item *rcdata;
2355      int ind;
2356 {
2357   const struct rcdata_item *ri;
2358
2359   indent (e, ind);
2360   fprintf (e, "BEGIN\n");
2361
2362   for (ri = rcdata; ri != NULL; ri = ri->next)
2363     {
2364       if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
2365         continue;
2366
2367       indent (e, ind + 2);
2368
2369       switch (ri->type)
2370         {
2371         default:
2372           abort ();
2373
2374         case RCDATA_WORD:
2375           fprintf (e, "%d", ri->u.word);
2376           break;
2377
2378         case RCDATA_DWORD:
2379           fprintf (e, "%luL", ri->u.dword);
2380           break;
2381
2382         case RCDATA_STRING:
2383           {
2384             const char *s;
2385             unsigned long i;
2386
2387             fprintf (e, "\"");
2388             s = ri->u.string.s;
2389             for (i = 0; i < ri->u.string.length; i++)
2390               {
2391                 if (ISPRINT (*s))
2392                   putc (*s, e);
2393                 else
2394                   fprintf (e, "\\%03o", *s);
2395               }
2396             fprintf (e, "\"");
2397             break;
2398           }
2399
2400         case RCDATA_WSTRING:
2401           fprintf (e, "L\"");
2402           unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
2403           fprintf (e, "\"");
2404           break;
2405
2406         case RCDATA_BUFFER:
2407           {
2408             unsigned long i;
2409             int first;
2410
2411             /* Assume little endian data.  */
2412
2413             first = 1;
2414             for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
2415               {
2416                 unsigned long l;
2417                 int j;
2418
2419                 if (! first)
2420                   indent (e, ind + 2);
2421                 l = ((((((ri->u.buffer.data[i + 3] << 8)
2422                          | ri->u.buffer.data[i + 2]) << 8)
2423                        | ri->u.buffer.data[i + 1]) << 8)
2424                      | ri->u.buffer.data[i]);
2425                 fprintf (e, "%luL", l);
2426                 if (i + 4 < ri->u.buffer.length || ri->next != NULL)
2427                   fprintf (e, ",");
2428                 for (j = 0; j < 4; ++j)
2429                   if (! ISPRINT (ri->u.buffer.data[i + j])
2430                       && ri->u.buffer.data[i + j] != 0)
2431                     break;
2432                 if (j >= 4)
2433                   {
2434                     fprintf (e, "\t// ");
2435                     for (j = 0; j < 4; ++j)
2436                       {
2437                         if (! ISPRINT (ri->u.buffer.data[i + j]))
2438                           fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2439                         else
2440                           {
2441                             if (ri->u.buffer.data[i + j] == '\\')
2442                               fprintf (e, "\\");
2443                             fprintf (e, "%c", ri->u.buffer.data[i + j]);
2444                           }
2445                       }
2446                   }
2447                 fprintf (e, "\n");
2448                 first = 0;
2449               }
2450
2451             if (i + 1 < ri->u.buffer.length)
2452               {
2453                 int s;
2454                 int j;
2455
2456                 if (! first)
2457                   indent (e, ind + 2);
2458                 s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
2459                 fprintf (e, "%d", s);
2460                 if (i + 2 < ri->u.buffer.length || ri->next != NULL)
2461                   fprintf (e, ",");
2462                 for (j = 0; j < 2; ++j)
2463                   if (! ISPRINT (ri->u.buffer.data[i + j])
2464                       && ri->u.buffer.data[i + j] != 0)
2465                     break;
2466                 if (j >= 2)
2467                   {
2468                     fprintf (e, "\t// ");
2469                     for (j = 0; j < 2; ++j)
2470                       {
2471                         if (! ISPRINT (ri->u.buffer.data[i + j]))
2472                           fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2473                         else
2474                           {
2475                             if (ri->u.buffer.data[i + j] == '\\')
2476                               fprintf (e, "\\");
2477                             fprintf (e, "%c", ri->u.buffer.data[i + j]);
2478                           }
2479                       }
2480                   }
2481                 fprintf (e, "\n");
2482                 i += 2;
2483                 first = 0;
2484               }
2485
2486             if (i < ri->u.buffer.length)
2487               {
2488                 if (! first)
2489                   indent (e, ind + 2);
2490                 if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
2491                     && ISPRINT (ri->u.buffer.data[i]))
2492                   fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
2493                 else
2494                   fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
2495                 if (ri->next != NULL)
2496                   fprintf (e, ",");
2497                 fprintf (e, "\n");
2498                 first = 0;
2499               }
2500
2501             break;
2502           }
2503         }
2504
2505       if (ri->type != RCDATA_BUFFER)
2506         {
2507           if (ri->next != NULL)
2508             fprintf (e, ",");
2509           fprintf (e, "\n");
2510         }
2511     }
2512
2513   indent (e, ind);
2514   fprintf (e, "END\n");
2515 }
2516
2517 /* Write out a stringtable resource.  */
2518
2519 static void
2520 write_rc_stringtable (e, name, stringtable)
2521      FILE *e;
2522      const struct res_id *name;
2523      const struct stringtable *stringtable;
2524 {
2525   unsigned long offset;
2526   int i;
2527
2528   if (name != NULL && ! name->named)
2529     offset = (name->u.id - 1) << 4;
2530   else
2531     {
2532       fprintf (e, "// %s string table name\n",
2533                name == NULL ? "Missing" : "Invalid");
2534       offset = 0;
2535     }
2536
2537   fprintf (e, "BEGIN\n");
2538
2539   for (i = 0; i < 16; i++)
2540     {
2541       if (stringtable->strings[i].length != 0)
2542         {
2543           fprintf (e, "  %lu, \"", offset + i);
2544           unicode_print (e, stringtable->strings[i].string,
2545                          stringtable->strings[i].length);
2546           fprintf (e, "\"\n");
2547         }
2548     }
2549
2550   fprintf (e, "END\n");
2551 }
2552
2553 /* Write out a versioninfo resource.  */
2554
2555 static void
2556 write_rc_versioninfo (e, versioninfo)
2557      FILE *e;
2558      const struct versioninfo *versioninfo;
2559 {
2560   const struct fixed_versioninfo *f;
2561   const struct ver_info *vi;
2562
2563   f = versioninfo->fixed;
2564   if (f->file_version_ms != 0 || f->file_version_ls != 0)
2565     fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
2566              (f->file_version_ms >> 16) & 0xffff,
2567              f->file_version_ms & 0xffff,
2568              (f->file_version_ls >> 16) & 0xffff,
2569              f->file_version_ls & 0xffff);
2570   if (f->product_version_ms != 0 || f->product_version_ls != 0)
2571     fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
2572              (f->product_version_ms >> 16) & 0xffff,
2573              f->product_version_ms & 0xffff,
2574              (f->product_version_ls >> 16) & 0xffff,
2575              f->product_version_ls & 0xffff);
2576   if (f->file_flags_mask != 0)
2577     fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
2578   if (f->file_flags != 0)
2579     fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
2580   if (f->file_os != 0)
2581     fprintf (e, " FILEOS 0x%lx\n", f->file_os);
2582   if (f->file_type != 0)
2583     fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
2584   if (f->file_subtype != 0)
2585     fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
2586   if (f->file_date_ms != 0 || f->file_date_ls != 0)
2587     fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
2588
2589   fprintf (e, "BEGIN\n");
2590
2591   for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2592     {
2593       switch (vi->type)
2594         {
2595         case VERINFO_STRING:
2596           {
2597             const struct ver_stringinfo *vs;
2598
2599             fprintf (e, "  BLOCK \"StringFileInfo\"\n");
2600             fprintf (e, "  BEGIN\n");
2601             fprintf (e, "    BLOCK \"");
2602             unicode_print (e, vi->u.string.language, -1);
2603             fprintf (e, "\"\n");
2604             fprintf (e, "    BEGIN\n");
2605
2606             for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2607               {
2608                 fprintf (e, "      VALUE \"");
2609                 unicode_print (e, vs->key, -1);
2610                 fprintf (e, "\", \"");
2611                 unicode_print (e, vs->value, -1);
2612                 fprintf (e, "\"\n");
2613               }
2614
2615             fprintf (e, "    END\n");
2616             fprintf (e, "  END\n");
2617             break;
2618           }
2619
2620         case VERINFO_VAR:
2621           {
2622             const struct ver_varinfo *vv;
2623
2624             fprintf (e, "  BLOCK \"VarFileInfo\"\n");
2625             fprintf (e, "  BEGIN\n");
2626             fprintf (e, "    VALUE \"");
2627             unicode_print (e, vi->u.var.key, -1);
2628             fprintf (e, "\"");
2629
2630             for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2631               fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
2632                        vv->charset);
2633
2634             fprintf (e, "\n  END\n");
2635
2636             break;
2637           }
2638         }
2639     }
2640
2641   fprintf (e, "END\n");
2642 }
2643
2644 /* Write out data which would normally be read from a file.  */
2645
2646 static void
2647 write_rc_filedata (e, length, data)
2648      FILE *e;
2649      unsigned long length;
2650      const unsigned char *data;
2651 {
2652   unsigned long i;
2653
2654   for (i = 0; i + 15 < length; i += 16)
2655     {
2656       fprintf (e, "// %4lx: ", i);
2657       fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
2658                data[i + 0], data[i + 1], data[i + 2], data[i + 3],
2659                data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
2660       fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2661                data[i +  8], data[i +  9], data[i + 10], data[i + 11],
2662                data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
2663     }
2664
2665   if (i < length)
2666     {
2667       fprintf (e, "// %4lx:", i);
2668       while (i < length)
2669         {
2670           fprintf (e, " %02x", data[i]);
2671           ++i;
2672         }
2673       fprintf (e, "\n");
2674     }
2675 }