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