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