* resrc.c (close_input_stream): delete extraneous logic
[platform/upstream/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 -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 & 0xff, (re->id.u.id >> 8) & 0xff);
1596               *language = re->id.u.id;
1597             }
1598           break;
1599
1600         default:
1601           break;
1602         }
1603
1604       if (re->subdir)
1605         write_rc_subdir (e, re, type, name, language, level);
1606       else
1607         {
1608           if (level == 3)
1609             {
1610               /* This is the normal case: the three levels are
1611                  TYPE/NAME/LANGUAGE.  NAME will have been set at level
1612                  2, and represents the name to use.  We probably just
1613                  set LANGUAGE, and it will probably match what the
1614                  resource itself records if anything.  */
1615               write_rc_resource (e, type, name, re->u.res, language);
1616             }
1617           else
1618             {
1619               fprintf (e, "// Resource at unexpected level %d\n", level);
1620               write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
1621                                  language);
1622             }
1623         }
1624     }
1625 }
1626
1627 /* Write out a subdirectory entry.  E is the file to write to.  RE is
1628    the subdirectory entry.  TYPE and NAME are pointers to higher level
1629    IDs, or NULL.  LANGUAGE is a pointer to the current language.
1630    LEVEL is the level in the tree.  */
1631
1632 static void
1633 write_rc_subdir (e, re, type, name, language, level)
1634      FILE *e;
1635      const struct res_entry *re;
1636      const struct res_id *type;
1637      const struct res_id *name;
1638      int *language;
1639      int level;
1640 {
1641   fprintf (e, "\n");
1642   switch (level)
1643     {
1644     case 1:
1645       fprintf (e, "// Type: ");
1646       if (re->id.named)
1647         res_id_print (e, re->id, 1);
1648       else
1649         {
1650           const char *s;
1651
1652           switch (re->id.u.id)
1653             {
1654             case RT_CURSOR: s = "cursor"; break;
1655             case RT_BITMAP: s = "bitmap"; break;
1656             case RT_ICON: s = "icon"; break;
1657             case RT_MENU: s = "menu"; break;
1658             case RT_DIALOG: s = "dialog"; break;
1659             case RT_STRING: s = "stringtable"; break;
1660             case RT_FONTDIR: s = "fontdir"; break;
1661             case RT_FONT: s = "font"; break;
1662             case RT_ACCELERATOR: s = "accelerators"; break;
1663             case RT_RCDATA: s = "rcdata"; break;
1664             case RT_MESSAGETABLE: s = "messagetable"; break;
1665             case RT_GROUP_CURSOR: s = "group cursor"; break;
1666             case RT_GROUP_ICON: s = "group icon"; break;
1667             case RT_VERSION: s = "version"; break;
1668             case RT_DLGINCLUDE: s = "dlginclude"; break;
1669             case RT_PLUGPLAY: s = "plugplay"; break;
1670             case RT_VXD: s = "vxd"; break;
1671             case RT_ANICURSOR: s = "anicursor"; break;
1672             case RT_ANIICON: s = "aniicon"; break;
1673             default: s = NULL; break;
1674             }
1675
1676           if (s != NULL)
1677             fprintf (e, "%s", s);
1678           else
1679             res_id_print (e, re->id, 1);
1680         }
1681       fprintf (e, "\n");
1682       break;
1683
1684     case 2:
1685       fprintf (e, "// Name: ");
1686       res_id_print (e, re->id, 1);
1687       fprintf (e, "\n");
1688       break;
1689
1690     case 3:
1691       fprintf (e, "// Language: ");
1692       res_id_print (e, re->id, 1);
1693       fprintf (e, "\n");
1694       break;
1695
1696     default:
1697       fprintf (e, "// Level %d: ", level);
1698       res_id_print (e, re->id, 1);
1699       fprintf (e, "\n");
1700     }           
1701
1702   write_rc_directory (e, re->u.dir, type, name, language, level + 1);
1703 }
1704
1705 /* Write out a single resource.  E is the file to write to.  TYPE is a
1706    pointer to the type of the resource.  NAME is a pointer to the name
1707    of the resource; it will be NULL if there is a level mismatch.  RES
1708    is the resource data.  LANGUAGE is a pointer to the current
1709    language.  */
1710
1711 static void
1712 write_rc_resource (e, type, name, res, language)
1713      FILE *e;
1714      const struct res_id *type;
1715      const struct res_id *name;
1716      const struct res_resource *res;
1717      int *language;
1718 {
1719   const char *s;
1720   int rt;
1721   int menuex = 0;
1722
1723   fprintf (e, "\n");
1724
1725   switch (res->type)
1726     {
1727     default:
1728       abort ();
1729
1730     case RES_TYPE_ACCELERATOR:
1731       s = "ACCELERATOR";
1732       rt = RT_ACCELERATOR;
1733       break;
1734
1735     case RES_TYPE_BITMAP:
1736       s = "BITMAP";
1737       rt = RT_BITMAP;
1738       break;
1739
1740     case RES_TYPE_CURSOR:
1741       s = "CURSOR";
1742       rt = RT_CURSOR;
1743       break;
1744
1745     case RES_TYPE_GROUP_CURSOR:
1746       s = "GROUP_CURSOR";
1747       rt = RT_GROUP_CURSOR;
1748       break;
1749
1750     case RES_TYPE_DIALOG:
1751       if (extended_dialog (res->u.dialog))
1752         s = "DIALOGEX";
1753       else
1754         s = "DIALOG";
1755       rt = RT_DIALOG;
1756       break;
1757
1758     case RES_TYPE_FONT:
1759       s = "FONT";
1760       rt = RT_FONT;
1761       break;
1762
1763     case RES_TYPE_FONTDIR:
1764       s = "FONTDIR";
1765       rt = RT_FONTDIR;
1766       break;
1767
1768     case RES_TYPE_ICON:
1769       s = "ICON";
1770       rt = RT_ICON;
1771       break;
1772
1773     case RES_TYPE_GROUP_ICON:
1774       s = "GROUP_ICON";
1775       rt = RT_GROUP_ICON;
1776       break;
1777
1778     case RES_TYPE_MENU:
1779       if (extended_menu (res->u.menu))
1780         {
1781           s = "MENUEX";
1782           menuex = 1;
1783         }
1784       else
1785         {
1786           s = "MENU";
1787           menuex = 0;
1788         }
1789       rt = RT_MENU;
1790       break;
1791
1792     case RES_TYPE_MESSAGETABLE:
1793       s = "MESSAGETABLE";
1794       rt = RT_MESSAGETABLE;
1795       break;
1796
1797     case RES_TYPE_RCDATA:
1798       s = "RCDATA";
1799       rt = RT_RCDATA;
1800       break;
1801
1802     case RES_TYPE_STRINGTABLE:
1803       s = "STRINGTABLE";
1804       rt = RT_STRING;
1805       break;
1806
1807     case RES_TYPE_USERDATA:
1808       s = NULL;
1809       rt = 0;
1810       break;
1811
1812     case RES_TYPE_VERSIONINFO:
1813       s = "VERSIONINFO";
1814       rt = RT_VERSION;
1815       break;
1816     }
1817
1818   if (rt != 0
1819       && type != NULL
1820       && (type->named || type->u.id != (unsigned long) rt))
1821     {
1822       fprintf (e, "// Unexpected resource type mismatch: ");
1823       res_id_print (e, *type, 1);
1824       fprintf (e, " != %d", rt);
1825     }
1826
1827   if (res->coff_info.codepage != 0)
1828     fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
1829   if (res->coff_info.reserved != 0)
1830     fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
1831
1832   if (name != NULL)
1833     res_id_print (e, *name, 0);
1834   else
1835     fprintf (e, "??Unknown-Name??");
1836
1837   fprintf (e, " ");
1838   if (s != NULL)
1839     fprintf (e, "%s", s);
1840   else if (type != NULL)
1841     res_id_print (e, *type, 0);
1842   else
1843     fprintf (e, "??Unknown-Type??");
1844
1845   if (res->res_info.memflags != 0)
1846     {
1847       if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
1848         fprintf (e, " MOVEABLE");
1849       if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
1850         fprintf (e, " PURE");
1851       if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
1852         fprintf (e, " PRELOAD");
1853       if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
1854         fprintf (e, " DISCARDABLE");
1855     }
1856
1857   if (res->type == RES_TYPE_DIALOG)
1858     {
1859       fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
1860                res->u.dialog->width, res->u.dialog->height);
1861       if (res->u.dialog->ex != NULL
1862           && res->u.dialog->ex->help != 0)
1863         fprintf (e, ", %lu", res->u.dialog->ex->help);
1864     }
1865
1866   fprintf (e, "\n");
1867
1868   if ((res->res_info.language != 0 && res->res_info.language != *language)
1869       || res->res_info.characteristics != 0
1870       || res->res_info.version != 0)
1871     {
1872       int modifiers;
1873
1874       switch (res->type)
1875         {
1876         case RES_TYPE_ACCELERATOR:
1877         case RES_TYPE_DIALOG:
1878         case RES_TYPE_MENU:
1879         case RES_TYPE_RCDATA:
1880         case RES_TYPE_STRINGTABLE:
1881           modifiers = 1;
1882           break;
1883
1884         default:
1885           modifiers = 0;
1886           break;
1887         }
1888
1889       if (res->res_info.language != 0 && res->res_info.language != *language)
1890         fprintf (e, "%sLANGUAGE %d, %d\n",
1891                  modifiers ? "// " : "",
1892                  res->res_info.language & 0xff,
1893                  (res->res_info.language >> 8) & 0xff);
1894       if (res->res_info.characteristics != 0)
1895         fprintf (e, "%sCHARACTERISTICS %lu\n",
1896                  modifiers ? "// " : "",
1897                  res->res_info.characteristics);
1898       if (res->res_info.version != 0)
1899         fprintf (e, "%sVERSION %lu\n",
1900                  modifiers ? "// " : "",
1901                  res->res_info.version);
1902     }
1903
1904   switch (res->type)
1905     {
1906     default:
1907       abort ();
1908
1909     case RES_TYPE_ACCELERATOR:
1910       write_rc_accelerators (e, res->u.acc);
1911       break;
1912
1913     case RES_TYPE_CURSOR:
1914       write_rc_cursor (e, res->u.cursor);
1915       break;
1916
1917     case RES_TYPE_GROUP_CURSOR:
1918       write_rc_group_cursor (e, res->u.group_cursor);
1919       break;
1920
1921     case RES_TYPE_DIALOG:
1922       write_rc_dialog (e, res->u.dialog);
1923       break;
1924
1925     case RES_TYPE_FONTDIR:
1926       write_rc_fontdir (e, res->u.fontdir);
1927       break;
1928
1929     case RES_TYPE_GROUP_ICON:
1930       write_rc_group_icon (e, res->u.group_icon);
1931       break;
1932
1933     case RES_TYPE_MENU:
1934       write_rc_menu (e, res->u.menu, menuex);
1935       break;
1936
1937     case RES_TYPE_RCDATA:
1938       write_rc_rcdata (e, res->u.rcdata, 0);
1939       break;
1940
1941     case RES_TYPE_STRINGTABLE:
1942       write_rc_stringtable (e, name, res->u.stringtable);
1943       break;
1944
1945     case RES_TYPE_USERDATA:
1946       write_rc_rcdata (e, res->u.userdata, 0);
1947       break;
1948
1949     case RES_TYPE_VERSIONINFO:
1950       write_rc_versioninfo (e, res->u.versioninfo);
1951       break;
1952
1953     case RES_TYPE_BITMAP:
1954     case RES_TYPE_FONT:
1955     case RES_TYPE_ICON:
1956     case RES_TYPE_MESSAGETABLE:
1957       write_rc_filedata (e, res->u.data.length, res->u.data.data);
1958       break;
1959     }
1960 }
1961
1962 /* Write out accelerator information.  */
1963
1964 static void
1965 write_rc_accelerators (e, accelerators)
1966      FILE *e;
1967      const struct accelerator *accelerators;
1968 {
1969   const struct accelerator *acc;
1970
1971   fprintf (e, "BEGIN\n");
1972   for (acc = accelerators; acc != NULL; acc = acc->next)
1973     {
1974       int printable;
1975
1976       fprintf (e, "  ");
1977
1978       if ((acc->key & 0x7f) == acc->key
1979           && isprint ((unsigned char) acc->key)
1980           && (acc->flags & ACC_VIRTKEY) == 0)
1981         {
1982           fprintf (e, "\"%c\"", acc->key);
1983           printable = 1;
1984         }
1985       else
1986         {
1987           fprintf (e, "%d", acc->key);
1988           printable = 0;
1989         }
1990
1991       fprintf (e, ", %d", acc->id);
1992
1993       if (! printable)
1994         {
1995           if ((acc->flags & ACC_VIRTKEY) != 0)
1996             fprintf (e, ", VIRTKEY");
1997           else
1998             fprintf (e, ", ASCII");
1999         }
2000
2001       if ((acc->flags & ACC_SHIFT) != 0)
2002         fprintf (e, ", SHIFT");
2003       if ((acc->flags & ACC_CONTROL) != 0)
2004         fprintf (e, ", CONTROL");
2005       if ((acc->flags & ACC_ALT) != 0)
2006         fprintf (e, ", ALT");
2007
2008       fprintf (e, "\n");
2009     }
2010
2011   fprintf (e, "END\n");
2012 }
2013
2014 /* Write out cursor information.  This would normally be in a separate
2015    file, which the rc file would include.  */
2016
2017 static void
2018 write_rc_cursor (e, cursor)
2019      FILE *e;
2020      const struct cursor *cursor;
2021 {
2022   fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
2023            cursor->yhotspot);
2024   write_rc_filedata (e, cursor->length, cursor->data);
2025 }
2026
2027 /* Write out group cursor data.  This would normally be built from the
2028    cursor data.  */
2029
2030 static void
2031 write_rc_group_cursor (e, group_cursor)
2032      FILE *e;
2033      const struct group_cursor *group_cursor;
2034 {
2035   const struct group_cursor *gc;
2036
2037   for (gc = group_cursor; gc != NULL; gc = gc->next)
2038     {
2039       fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
2040              gc->width, gc->height, gc->planes, gc->bits);
2041       fprintf (e, "// data bytes: %lu; index: %d\n",
2042                gc->bytes, gc->index);
2043     }
2044 }
2045
2046 /* Write dialog data.  */
2047
2048 static void
2049 write_rc_dialog (e, dialog)
2050      FILE *e;
2051      const struct dialog *dialog;
2052 {
2053   const struct dialog_control *control;
2054
2055   if (dialog->style != 0)
2056     fprintf (e, "STYLE 0x%lx\n", dialog->style);
2057   if (dialog->exstyle != 0)
2058     fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
2059   if ((dialog->class.named && dialog->class.u.n.length > 0)
2060       || dialog->class.u.id != 0)
2061     {
2062       fprintf (e, "CLASS ");
2063       res_id_print (e, dialog->class, 0);
2064       fprintf (e, "\n");
2065     }
2066   if (dialog->caption != NULL)
2067     {
2068       fprintf (e, "CAPTION \"");
2069       unicode_print (e, dialog->caption, -1);
2070       fprintf (e, "\"\n");
2071     }
2072   if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2073       || dialog->menu.u.id != 0)
2074     {
2075       fprintf (e, "MENU ");
2076       res_id_print (e, dialog->menu, 0);
2077       fprintf (e, "\n");
2078     }
2079   if (dialog->font != NULL)
2080     {
2081       fprintf (e, "FONT %d, \"", dialog->pointsize);
2082       unicode_print (e, dialog->font, -1);
2083       fprintf (e, "\"");
2084       if (dialog->ex != NULL
2085           && (dialog->ex->weight != 0 || dialog->ex->italic != 0))
2086         fprintf (e, ", %d, %d", dialog->ex->weight, dialog->ex->italic);
2087       fprintf (e, "\n");
2088     }
2089
2090   fprintf (e, "BEGIN\n");
2091
2092   for (control = dialog->controls; control != NULL; control = control->next)
2093     write_rc_dialog_control (e, control);
2094
2095   fprintf (e, "END\n");
2096 }
2097
2098 /* For each predefined control keyword, this table provides the class
2099    and the style.  */
2100
2101 struct control_info
2102 {
2103   const char *name;
2104   unsigned short class;
2105   unsigned long style;
2106 };
2107
2108 static const struct control_info control_info[] =
2109 {
2110   { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2111   { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2112   { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2113   { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2114   { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2115   { "CTEXT", CTL_STATIC, SS_CENTER },
2116   { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2117   { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2118   { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2119   { "ICON", CTL_STATIC, SS_ICON },
2120   { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2121   { "LTEXT", CTL_STATIC, SS_LEFT },
2122   { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2123   { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2124   { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2125   { "RTEXT", CTL_STATIC, SS_RIGHT },
2126   { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2127   { "STATE3", CTL_BUTTON, BS_3STATE },
2128   /* It's important that USERBUTTON come after all the other button
2129      types, so that it won't be matched too early.  */
2130   { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2131   { NULL, 0, 0 }
2132 };
2133
2134 /* Write a dialog control.  */
2135
2136 static void
2137 write_rc_dialog_control (e, control)
2138      FILE *e;
2139      const struct dialog_control *control;
2140 {
2141   const struct control_info *ci;
2142
2143   fprintf (e, "  ");
2144
2145   if (control->class.named)
2146     ci = NULL;
2147   else
2148     {
2149       for (ci = control_info; ci->name != NULL; ++ci)
2150         if (ci->class == control->class.u.id
2151             && (ci->style == (unsigned long) -1
2152                 || ci->style == (control->style & 0xff)))
2153           break;
2154     }
2155   if (ci == NULL)
2156     fprintf (e, "CONTROL");
2157   else if (ci->name != NULL)
2158     fprintf (e, "%s", ci->name);
2159   else
2160     fprintf (e, "CONTROL");
2161   
2162   if (control->text.named || control->text.u.id != 0)
2163     {
2164       fprintf (e, " ");
2165       res_id_print (e, control->text, 1);
2166       fprintf (e, ",");
2167     }
2168
2169   fprintf (e, " %d, ", control->id);
2170
2171   if (ci == NULL)
2172     {
2173       if (control->class.named)
2174         fprintf (e, "\"");
2175       res_id_print (e, control->class, 0);
2176       if (control->class.named)
2177         fprintf (e, "\"");
2178       fprintf (e, ", 0x%lx, ", control->style);
2179     }
2180
2181   fprintf (e, "%d, %d", control->x, control->y);
2182
2183   if (control->style != SS_ICON
2184       || control->exstyle != 0
2185       || control->width != 0
2186       || control->height != 0
2187       || control->help != 0)
2188     {
2189       fprintf (e, ", %d, %d", control->width, control->height);
2190
2191       /* FIXME: We don't need to print the style if it is the default.
2192          More importantly, in certain cases we actually need to turn
2193          off parts of the forced style, by using NOT.  */
2194       fprintf (e, ", 0x%lx", control->style);
2195
2196       if (control->exstyle != 0 || control->help != 0)
2197         fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
2198     }
2199
2200   fprintf (e, "\n");
2201
2202   if (control->data != NULL)
2203     write_rc_rcdata (e, control->data, 2);
2204 }
2205
2206 /* Write out font directory data.  This would normally be built from
2207    the font data.  */
2208
2209 static void
2210 write_rc_fontdir (e, fontdir)
2211      FILE *e;
2212      const struct fontdir *fontdir;
2213 {
2214   const struct fontdir *fc;
2215
2216   for (fc = fontdir; fc != NULL; fc = fc->next)
2217     {
2218       fprintf (e, "// Font index: %d\n", fc->index);
2219       write_rc_filedata (e, fc->length, fc->data);
2220     }
2221 }
2222
2223 /* Write out group icon data.  This would normally be built from the
2224    icon data.  */
2225
2226 static void
2227 write_rc_group_icon (e, group_icon)
2228      FILE *e;
2229      const struct group_icon *group_icon;
2230 {
2231   const struct group_icon *gi;
2232
2233   for (gi = group_icon; gi != NULL; gi = gi->next)
2234     {
2235       fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
2236                gi->width, gi->height, gi->colors, gi->planes, gi->bits);
2237       fprintf (e, "// data bytes: %lu; index: %d\n",
2238                gi->bytes, gi->index);
2239     }
2240 }
2241
2242 /* Write out a menu resource.  */
2243
2244 static void
2245 write_rc_menu (e, menu, menuex)
2246      FILE *e;
2247      const struct menu *menu;
2248      int menuex;
2249 {
2250   if (menu->help != 0)
2251     fprintf (e, "// Help ID: %lu\n", menu->help);
2252   write_rc_menuitems (e, menu->items, menuex, 0);
2253 }
2254
2255 /* Write out menuitems.  */
2256
2257 static void
2258 write_rc_menuitems (e, menuitems, menuex, ind)
2259      FILE *e;
2260      const struct menuitem *menuitems;
2261      int menuex;
2262      int ind;
2263 {
2264   const struct menuitem *mi;
2265
2266   indent (e, ind);
2267   fprintf (e, "BEGIN\n");
2268
2269   for (mi = menuitems; mi != NULL; mi = mi->next)
2270     {
2271       indent (e, ind + 2);
2272
2273       if (mi->popup == NULL)
2274         fprintf (e, "MENUITEM");
2275       else
2276         fprintf (e, "POPUP");
2277
2278       if (! menuex
2279           && mi->popup == NULL
2280           && mi->text == NULL
2281           && mi->type == 0
2282           && mi->id == 0)
2283         {
2284           fprintf (e, " SEPARATOR\n");
2285           continue;
2286         }
2287
2288       if (mi->text == NULL)
2289         fprintf (e, " \"\"");
2290       else
2291         {
2292           fprintf (e, " \"");
2293           unicode_print (e, mi->text, -1);
2294           fprintf (e, "\"");
2295         }
2296
2297       if (! menuex)
2298         {
2299           if (mi->popup == NULL)
2300             fprintf (e, ", %d", mi->id);
2301
2302           if ((mi->type & MENUITEM_CHECKED) != 0)
2303             fprintf (e, ", CHECKED");
2304           if ((mi->type & MENUITEM_GRAYED) != 0)
2305             fprintf (e, ", GRAYED");
2306           if ((mi->type & MENUITEM_HELP) != 0)
2307             fprintf (e, ", HELP");
2308           if ((mi->type & MENUITEM_INACTIVE) != 0)
2309             fprintf (e, ", INACTIVE");
2310           if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2311             fprintf (e, ", MENUBARBREAK");
2312           if ((mi->type & MENUITEM_MENUBREAK) != 0)
2313             fprintf (e, ", MENUBREAK");
2314         }
2315       else
2316         {
2317           if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2318             {
2319               fprintf (e, ", %d", mi->id);
2320               if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2321                 {
2322                   fprintf (e, ", %lu", mi->type);
2323                   if (mi->state != 0 || mi->help != 0)
2324                     {
2325                       fprintf (e, ", %lu", mi->state);
2326                       if (mi->help != 0)
2327                         fprintf (e, ", %lu", mi->help);
2328                     }
2329                 }
2330             }
2331         }
2332
2333       fprintf (e, "\n");
2334
2335       if (mi->popup != NULL)
2336         write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2337     }
2338
2339   indent (e, ind);
2340   fprintf (e, "END\n");
2341 }
2342
2343 /* Write out an rcdata resource.  This is also used for other types of
2344    resources that need to print arbitrary data.  */
2345
2346 static void
2347 write_rc_rcdata (e, rcdata, ind)
2348      FILE *e;
2349      const struct rcdata_item *rcdata;
2350      int ind;
2351 {
2352   const struct rcdata_item *ri;
2353
2354   indent (e, ind);
2355   fprintf (e, "BEGIN\n");
2356
2357   for (ri = rcdata; ri != NULL; ri = ri->next)
2358     {
2359       if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
2360         continue;
2361
2362       indent (e, ind + 2);
2363
2364       switch (ri->type)
2365         {
2366         default:
2367           abort ();
2368
2369         case RCDATA_WORD:
2370           fprintf (e, "%d", ri->u.word);
2371           break;
2372
2373         case RCDATA_DWORD:
2374           fprintf (e, "%luL", ri->u.dword);
2375           break;
2376
2377         case RCDATA_STRING:
2378           {
2379             const char *s;
2380             unsigned long i;
2381
2382             fprintf (e, "\"");
2383             s = ri->u.string.s;
2384             for (i = 0; i < ri->u.string.length; i++)
2385               {
2386                 if (isprint ((unsigned char) *s))
2387                   putc (*s, e);
2388                 else
2389                   fprintf (e, "\\%03o", *s);
2390               }
2391             fprintf (e, "\"");
2392             break;
2393           }
2394
2395         case RCDATA_WSTRING:
2396           fprintf (e, "L\"");
2397           unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
2398           fprintf (e, "\"");
2399           break;
2400
2401         case RCDATA_BUFFER:
2402           {
2403             unsigned long i;
2404             int first;
2405
2406             /* Assume little endian data.  */
2407
2408             first = 1;
2409             for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
2410               {
2411                 unsigned long l;
2412                 int j;
2413
2414                 if (! first)
2415                   indent (e, ind + 2);
2416                 l = ((((((ri->u.buffer.data[i + 3] << 8)
2417                          | ri->u.buffer.data[i + 2]) << 8)
2418                        | ri->u.buffer.data[i + 1]) << 8)
2419                      | ri->u.buffer.data[i]);
2420                 fprintf (e, "%luL", l);
2421                 if (i + 4 < ri->u.buffer.length || ri->next != NULL)
2422                   fprintf (e, ",");
2423                 for (j = 0; j < 4; ++j)
2424                   if (! isprint (ri->u.buffer.data[i + j])
2425                       && ri->u.buffer.data[i + j] != 0)
2426                     break;
2427                 if (j >= 4)
2428                   {
2429                     fprintf (e, "\t// ");
2430                     for (j = 0; j < 4; ++j)
2431                       {
2432                         if (! isprint (ri->u.buffer.data[i + j]))
2433                           fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2434                         else
2435                           {
2436                             if (ri->u.buffer.data[i + j] == '\\')
2437                               fprintf (e, "\\");
2438                             fprintf (e, "%c", ri->u.buffer.data[i + j]);
2439                           }
2440                       }
2441                   }
2442                 fprintf (e, "\n");
2443                 first = 0;
2444               }
2445
2446             if (i + 1 < ri->u.buffer.length)
2447               {
2448                 int s;
2449                 int j;
2450
2451                 if (! first)
2452                   indent (e, ind + 2);
2453                 s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
2454                 fprintf (e, "%d", s);
2455                 if (i + 2 < ri->u.buffer.length || ri->next != NULL)
2456                   fprintf (e, ",");
2457                 for (j = 0; j < 2; ++j)
2458                   if (! isprint (ri->u.buffer.data[i + j])
2459                       && ri->u.buffer.data[i + j] != 0)
2460                     break;
2461                 if (j >= 2)
2462                   {
2463                     fprintf (e, "\t// ");
2464                     for (j = 0; j < 2; ++j)
2465                       {
2466                         if (! isprint (ri->u.buffer.data[i + j]))
2467                           fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2468                         else
2469                           {
2470                             if (ri->u.buffer.data[i + j] == '\\')
2471                               fprintf (e, "\\");
2472                             fprintf (e, "%c", ri->u.buffer.data[i + j]);
2473                           }
2474                       }
2475                   }
2476                 fprintf (e, "\n");
2477                 i += 2;
2478                 first = 0;
2479               }
2480
2481             if (i < ri->u.buffer.length)
2482               {
2483                 if (! first)
2484                   indent (e, ind + 2);
2485                 if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
2486                     && isprint (ri->u.buffer.data[i]))
2487                   fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
2488                 else
2489                   fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
2490                 if (ri->next != NULL)
2491                   fprintf (e, ",");
2492                 fprintf (e, "\n");
2493                 first = 0;
2494               }
2495
2496             break;
2497           }
2498         }
2499
2500       if (ri->type != RCDATA_BUFFER)
2501         {
2502           if (ri->next != NULL)
2503             fprintf (e, ",");
2504           fprintf (e, "\n");
2505         }
2506     }
2507
2508   indent (e, ind);
2509   fprintf (e, "END\n");
2510 }
2511
2512 /* Write out a stringtable resource.  */
2513
2514 static void
2515 write_rc_stringtable (e, name, stringtable)
2516      FILE *e;
2517      const struct res_id *name;
2518      const struct stringtable *stringtable;
2519 {
2520   unsigned long offset;
2521   int i;
2522
2523   if (name != NULL && ! name->named)
2524     offset = (name->u.id - 1) << 4;
2525   else
2526     {
2527       fprintf (e, "// %s string table name\n",
2528                name == NULL ? "Missing" : "Invalid");
2529       offset = 0;
2530     }
2531
2532   fprintf (e, "BEGIN\n");
2533
2534   for (i = 0; i < 16; i++)
2535     {
2536       if (stringtable->strings[i].length != 0)
2537         {
2538           fprintf (e, "  %lu, \"", offset + i);
2539           unicode_print (e, stringtable->strings[i].string,
2540                          stringtable->strings[i].length);
2541           fprintf (e, "\"\n");
2542         }
2543     }
2544
2545   fprintf (e, "END\n");
2546 }
2547
2548 /* Write out a versioninfo resource.  */
2549
2550 static void
2551 write_rc_versioninfo (e, versioninfo)
2552      FILE *e;
2553      const struct versioninfo *versioninfo;
2554 {
2555   const struct fixed_versioninfo *f;
2556   const struct ver_info *vi;
2557
2558   f = versioninfo->fixed;
2559   if (f->file_version_ms != 0 || f->file_version_ls != 0)
2560     fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
2561              (f->file_version_ms >> 16) & 0xffff,
2562              f->file_version_ms & 0xffff,
2563              (f->file_version_ls >> 16) & 0xffff,
2564              f->file_version_ls & 0xffff);
2565   if (f->product_version_ms != 0 || f->product_version_ls != 0)
2566     fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
2567              (f->product_version_ms >> 16) & 0xffff,
2568              f->product_version_ms & 0xffff,
2569              (f->product_version_ls >> 16) & 0xffff,
2570              f->product_version_ls & 0xffff);
2571   if (f->file_flags_mask != 0)
2572     fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
2573   if (f->file_flags != 0)
2574     fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
2575   if (f->file_os != 0)
2576     fprintf (e, " FILEOS 0x%lx\n", f->file_os);
2577   if (f->file_type != 0)
2578     fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
2579   if (f->file_subtype != 0)
2580     fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
2581   if (f->file_date_ms != 0 || f->file_date_ls != 0)
2582     fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
2583
2584   fprintf (e, "BEGIN\n");
2585
2586   for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2587     {
2588       switch (vi->type)
2589         {
2590         case VERINFO_STRING:
2591           {
2592             const struct ver_stringinfo *vs;
2593
2594             fprintf (e, "  BLOCK \"StringFileInfo\"\n");
2595             fprintf (e, "  BEGIN\n");
2596             fprintf (e, "    BLOCK \"");
2597             unicode_print (e, vi->u.string.language, -1);
2598             fprintf (e, "\"\n");
2599             fprintf (e, "    BEGIN\n");
2600
2601             for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2602               {
2603                 fprintf (e, "      VALUE \"");
2604                 unicode_print (e, vs->key, -1);
2605                 fprintf (e, "\", \"");
2606                 unicode_print (e, vs->value, -1);
2607                 fprintf (e, "\"\n");
2608               }
2609
2610             fprintf (e, "    END\n");
2611             fprintf (e, "  END\n");
2612             break;
2613           }
2614
2615         case VERINFO_VAR:
2616           {
2617             const struct ver_varinfo *vv;
2618
2619             fprintf (e, "  BLOCK \"VarFileInfo\"\n");
2620             fprintf (e, "  BEGIN\n");
2621             fprintf (e, "    VALUE \"");
2622             unicode_print (e, vi->u.var.key, -1);
2623             fprintf (e, "\"");
2624
2625             for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2626               fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
2627                        vv->charset);
2628
2629             fprintf (e, "\n  END\n");
2630
2631             break;
2632           }
2633         }
2634     }
2635
2636   fprintf (e, "END\n");
2637 }
2638
2639 /* Write out data which would normally be read from a file.  */
2640
2641 static void
2642 write_rc_filedata (e, length, data)
2643      FILE *e;
2644      unsigned long length;
2645      const unsigned char *data;
2646 {
2647   unsigned long i;
2648
2649   for (i = 0; i + 15 < length; i += 16)
2650     {
2651       fprintf (e, "// %4lx: ", i);
2652       fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
2653                data[i + 0], data[i + 1], data[i + 2], data[i + 3],
2654                data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
2655       fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2656                data[i +  8], data[i +  9], data[i + 10], data[i + 11],
2657                data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
2658     }
2659
2660   if (i < length)
2661     {
2662       fprintf (e, "// %4lx:", i);
2663       while (i < length)
2664         {
2665           fprintf (e, " %02x", data[i]);
2666           ++i;
2667         }
2668       fprintf (e, "\n");
2669     }
2670 }