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