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