Fix C90 conversion
[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
254 /* Close reponse file. */
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
1043 cg->planes = 1;
1044 cg->bits = 0;
1045 while ((1 << cg->bits) < cg->colors)
1046 ++cg->bits;
1047
1048 cg->bytes = icondirs[i].bytes;
1049 cg->index = first_icon + i + 1;
1050
1051 *pp = cg;
1052 pp = &(*pp)->next;
1053 }
1054
1055 free (icondirs);
1056
1057 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1058 resinfo->language, 0);
1059 r->type = RES_TYPE_GROUP_ICON;
1060 r->u.group_icon = first;
1061 r->res_info = *resinfo;
1062}
1063
1064/* Define a menu resource. */
1065
1066void
2da42df6
AJ
1067define_menu (struct res_id id, const struct res_res_info *resinfo,
1068 struct menuitem *menuitems)
252b5132
RH
1069{
1070 struct menu *m;
1071 struct res_resource *r;
1072
1073 m = (struct menu *) res_alloc (sizeof *m);
1074 m->items = menuitems;
1075 m->help = 0;
1076
1077 r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1078 r->type = RES_TYPE_MENU;
1079 r->u.menu = m;
1080 r->res_info = *resinfo;
1081}
1082
1083/* Define a menu item. This does not define a resource, but merely
1084 allocates and fills in a structure. */
1085
1086struct menuitem *
2da42df6
AJ
1087define_menuitem (const char *text, int menuid, unsigned long type,
1088 unsigned long state, unsigned long help,
1089 struct menuitem *menuitems)
252b5132
RH
1090{
1091 struct menuitem *mi;
1092
1093 mi = (struct menuitem *) res_alloc (sizeof *mi);
1094 mi->next = NULL;
1095 mi->type = type;
1096 mi->state = state;
1097 mi->id = menuid;
1098 if (text == NULL)
1099 mi->text = NULL;
1100 else
1101 unicode_from_ascii ((int *) NULL, &mi->text, text);
1102 mi->help = help;
1103 mi->popup = menuitems;
1104 return mi;
1105}
1106
1107/* Define a messagetable resource. */
1108
1109void
2da42df6
AJ
1110define_messagetable (struct res_id id, const struct res_res_info *resinfo,
1111 const char *filename)
252b5132
RH
1112{
1113 FILE *e;
1114 char *real_filename;
1115 struct stat s;
1116 unsigned char *data;
1117 struct res_resource *r;
1118
1119 e = open_file_search (filename, FOPEN_RB, "messagetable file",
1120 &real_filename);
1121
1122 if (stat (real_filename, &s) < 0)
1123 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1124 strerror (errno));
1125
1126 data = (unsigned char *) res_alloc (s.st_size);
1127
1128 get_data (e, data, s.st_size, real_filename);
1129
1130 fclose (e);
1131 free (real_filename);
1132
1133 r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1134 resinfo->language, 0);
1135
1136 r->type = RES_TYPE_MESSAGETABLE;
1137 r->u.data.length = s.st_size;
1138 r->u.data.data = data;
1139 r->res_info = *resinfo;
1140}
1141
1142/* Define an rcdata resource. */
1143
1144void
2da42df6
AJ
1145define_rcdata (struct res_id id, const struct res_res_info *resinfo,
1146 struct rcdata_item *data)
252b5132
RH
1147{
1148 struct res_resource *r;
1149
1150 r = define_standard_resource (&resources, RT_RCDATA, id,
1151 resinfo->language, 0);
1152 r->type = RES_TYPE_RCDATA;
1153 r->u.rcdata = data;
1154 r->res_info = *resinfo;
1155}
1156
1157/* Create an rcdata item holding a string. */
1158
1159struct rcdata_item *
2da42df6 1160define_rcdata_string (const char *string, unsigned long len)
252b5132
RH
1161{
1162 struct rcdata_item *ri;
1163 char *s;
1164
1165 ri = (struct rcdata_item *) res_alloc (sizeof *ri);
1166 ri->next = NULL;
1167 ri->type = RCDATA_STRING;
1168 ri->u.string.length = len;
1169 s = (char *) res_alloc (len);
1170 memcpy (s, string, len);
1171 ri->u.string.s = s;
1172
1173 return ri;
1174}
1175
1176/* Create an rcdata item holding a number. */
1177
1178struct rcdata_item *
2da42df6 1179define_rcdata_number (unsigned long val, int dword)
252b5132
RH
1180{
1181 struct rcdata_item *ri;
1182
1183 ri = (struct rcdata_item *) res_alloc (sizeof *ri);
1184 ri->next = NULL;
1185 ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1186 ri->u.word = val;
1187
1188 return ri;
1189}
1190
1191/* Define a stringtable resource. This is called for each string
1192 which appears in a STRINGTABLE statement. */
1193
1194void
2da42df6
AJ
1195define_stringtable (const struct res_res_info *resinfo,
1196 unsigned long stringid, const char *string)
252b5132
RH
1197{
1198 struct res_id id;
1199 struct res_resource *r;
1200
1201 id.named = 0;
1202 id.u.id = (stringid >> 4) + 1;
1203 r = define_standard_resource (&resources, RT_STRING, id,
1204 resinfo->language, 1);
1205
1206 if (r->type == RES_TYPE_UNINITIALIZED)
1207 {
1208 int i;
1209
1210 r->type = RES_TYPE_STRINGTABLE;
1211 r->u.stringtable = ((struct stringtable *)
1212 res_alloc (sizeof (struct stringtable)));
1213 for (i = 0; i < 16; i++)
1214 {
1215 r->u.stringtable->strings[i].length = 0;
1216 r->u.stringtable->strings[i].string = NULL;
1217 }
1218
1219 r->res_info = *resinfo;
1220 }
1221
1222 unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
1223 &r->u.stringtable->strings[stringid & 0xf].string,
1224 string);
1225}
1226
1227/* Define a user data resource where the data is in the rc file. */
1228
1229void
2da42df6
AJ
1230define_user_data (struct res_id id, struct res_id type,
1231 const struct res_res_info *resinfo,
1232 struct rcdata_item *data)
252b5132
RH
1233{
1234 struct res_id ids[3];
1235 struct res_resource *r;
1236
1237 ids[0] = type;
1238 ids[1] = id;
1239 ids[2].named = 0;
1240 ids[2].u.id = resinfo->language;
1241
1242 r = define_resource (&resources, 3, ids, 0);
1243 r->type = RES_TYPE_USERDATA;
1244 r->u.userdata = data;
1245 r->res_info = *resinfo;
1246}
1247
1248/* Define a user data resource where the data is in a file. */
1249
1250void
2da42df6
AJ
1251define_user_file (struct res_id id, struct res_id type,
1252 const struct res_res_info *resinfo, const char *filename)
252b5132
RH
1253{
1254 FILE *e;
1255 char *real_filename;
1256 struct stat s;
1257 unsigned char *data;
1258 struct res_id ids[3];
1259 struct res_resource *r;
1260
1261 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
1262
1263 if (stat (real_filename, &s) < 0)
1264 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1265 strerror (errno));
1266
1267 data = (unsigned char *) res_alloc (s.st_size);
1268
1269 get_data (e, data, s.st_size, real_filename);
1270
1271 fclose (e);
1272 free (real_filename);
1273
1274 ids[0] = type;
1275 ids[1] = id;
1276 ids[2].named = 0;
1277 ids[2].u.id = resinfo->language;
1278
1279 r = define_resource (&resources, 3, ids, 0);
1280 r->type = RES_TYPE_USERDATA;
1281 r->u.userdata = ((struct rcdata_item *)
1282 res_alloc (sizeof (struct rcdata_item)));
1283 r->u.userdata->next = NULL;
1284 r->u.userdata->type = RCDATA_BUFFER;
1285 r->u.userdata->u.buffer.length = s.st_size;
1286 r->u.userdata->u.buffer.data = data;
1287 r->res_info = *resinfo;
1288}
1289
1290/* Define a versioninfo resource. */
1291
1292void
2da42df6
AJ
1293define_versioninfo (struct res_id id, int language,
1294 struct fixed_versioninfo *fixedverinfo,
1295 struct ver_info *verinfo)
252b5132
RH
1296{
1297 struct res_resource *r;
1298
1299 r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1300 r->type = RES_TYPE_VERSIONINFO;
1301 r->u.versioninfo = ((struct versioninfo *)
1302 res_alloc (sizeof (struct versioninfo)));
1303 r->u.versioninfo->fixed = fixedverinfo;
1304 r->u.versioninfo->var = verinfo;
1305 r->res_info.language = language;
1306}
1307
1308/* Add string version info to a list of version information. */
1309
1310struct ver_info *
2da42df6
AJ
1311append_ver_stringfileinfo (struct ver_info *verinfo, const char *language,
1312 struct ver_stringinfo *strings)
252b5132
RH
1313{
1314 struct ver_info *vi, **pp;
1315
1316 vi = (struct ver_info *) res_alloc (sizeof *vi);
1317 vi->next = NULL;
1318 vi->type = VERINFO_STRING;
1319 unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
1320 vi->u.string.strings = strings;
1321
1322 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1323 ;
1324 *pp = vi;
1325
1326 return verinfo;
1327}
1328
1329/* Add variable version info to a list of version information. */
1330
1331struct ver_info *
2da42df6
AJ
1332append_ver_varfileinfo (struct ver_info *verinfo, const char *key,
1333 struct ver_varinfo *var)
252b5132
RH
1334{
1335 struct ver_info *vi, **pp;
1336
1337 vi = (struct ver_info *) res_alloc (sizeof *vi);
1338 vi->next = NULL;
1339 vi->type = VERINFO_VAR;
1340 unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
1341 vi->u.var.var = var;
1342
1343 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1344 ;
1345 *pp = vi;
1346
1347 return verinfo;
1348}
1349
1350/* Append version string information to a list. */
1351
1352struct ver_stringinfo *
2da42df6
AJ
1353append_verval (struct ver_stringinfo *strings, const char *key,
1354 const char *value)
252b5132
RH
1355{
1356 struct ver_stringinfo *vs, **pp;
1357
1358 vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
1359 vs->next = NULL;
1360 unicode_from_ascii ((int *) NULL, &vs->key, key);
1361 unicode_from_ascii ((int *) NULL, &vs->value, value);
1362
1363 for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1364 ;
1365 *pp = vs;
1366
1367 return strings;
1368}
1369
1370/* Append version variable information to a list. */
1371
1372struct ver_varinfo *
2da42df6
AJ
1373append_vertrans (struct ver_varinfo *var, unsigned long language,
1374 unsigned long charset)
252b5132
RH
1375{
1376 struct ver_varinfo *vv, **pp;
1377
1378 vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
1379 vv->next = NULL;
1380 vv->language = language;
1381 vv->charset = charset;
1382
1383 for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1384 ;
1385 *pp = vv;
1386
1387 return var;
1388}
1389\f
1390/* Local functions used to write out an rc file. */
1391
2da42df6 1392static void indent (FILE *, int);
252b5132 1393static void write_rc_directory
2da42df6
AJ
1394 (FILE *, const struct res_directory *, const struct res_id *,
1395 const struct res_id *, int *, int);
252b5132 1396static void write_rc_subdir
2da42df6
AJ
1397 (FILE *, const struct res_entry *, const struct res_id *,
1398 const struct res_id *, int *, int);
252b5132 1399static void write_rc_resource
2da42df6
AJ
1400 (FILE *, const struct res_id *, const struct res_id *,
1401 const struct res_resource *, int *);
1402static void write_rc_accelerators (FILE *, const struct accelerator *);
1403static void write_rc_cursor (FILE *, const struct cursor *);
1404static void write_rc_group_cursor (FILE *, const struct group_cursor *);
1405static void write_rc_dialog (FILE *, const struct dialog *);
1406static void write_rc_dialog_control (FILE *, const struct dialog_control *);
1407static void write_rc_fontdir (FILE *, const struct fontdir *);
1408static void write_rc_group_icon (FILE *, const struct group_icon *);
1409static void write_rc_menu (FILE *, const struct menu *, int);
1410static void write_rc_menuitems (FILE *, const struct menuitem *, int, int);
1411static void write_rc_rcdata (FILE *, const struct rcdata_item *, int);
252b5132 1412static void write_rc_stringtable
2da42df6
AJ
1413 (FILE *, const struct res_id *, const struct stringtable *);
1414static void write_rc_versioninfo (FILE *, const struct versioninfo *);
1415static void write_rc_filedata (FILE *, unsigned long, const unsigned char *);
252b5132
RH
1416
1417/* Indent a given number of spaces. */
1418
1419static void
2da42df6 1420indent (FILE *e, int c)
252b5132
RH
1421{
1422 int i;
1423
1424 for (i = 0; i < c; i++)
1425 putc (' ', e);
1426}
1427
1428/* Dump the resources we have read in the format of an rc file.
1429
1430 Actually, we don't use the format of an rc file, because it's way
1431 too much of a pain--for example, we'd have to write icon resources
1432 into a file and refer to that file. We just generate a readable
1433 format that kind of looks like an rc file, and is useful for
1434 understanding the contents of a resource file. Someday we may want
1435 to generate an rc file which the rc compiler can read; if that day
1436 comes, this code will have to be fixed up. */
1437
1438void
2da42df6 1439write_rc_file (const char *filename, const struct res_directory *resources)
252b5132
RH
1440{
1441 FILE *e;
1442 int language;
1443
1444 if (filename == NULL)
1445 e = stdout;
1446 else
1447 {
1448 e = fopen (filename, FOPEN_WT);
1449 if (e == NULL)
1450 fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1451 }
1452
1453 language = -1;
1454 write_rc_directory (e, resources, (const struct res_id *) NULL,
1455 (const struct res_id *) NULL, &language, 1);
1456}
1457
1458/* Write out a directory. E is the file to write to. RD is the
1459 directory. TYPE is a pointer to the level 1 ID which serves as the
1460 resource type. NAME is a pointer to the level 2 ID which serves as
1461 an individual resource name. LANGUAGE is a pointer to the current
1462 language. LEVEL is the level in the tree. */
1463
1464static void
2da42df6
AJ
1465write_rc_directory (FILE *e, const struct res_directory *rd,
1466 const struct res_id *type, const struct res_id *name,
1467 int *language, int level)
252b5132
RH
1468{
1469 const struct res_entry *re;
1470
1471 /* Print out some COFF information that rc files can't represent. */
1472
1473 if (rd->time != 0)
1474 fprintf (e, "// Time stamp: %lu\n", rd->time);
1475 if (rd->characteristics != 0)
1476 fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
1477 if (rd->major != 0 || rd->minor != 0)
1478 fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
1479
1480 for (re = rd->entries; re != NULL; re = re->next)
1481 {
1482 switch (level)
1483 {
1484 case 1:
1485 /* If we're at level 1, the key of this resource is the
1486 type. This normally duplicates the information we have
1487 stored with the resource itself, but we need to remember
1488 the type if this is a user define resource type. */
1489 type = &re->id;
1490 break;
1491
1492 case 2:
1493 /* If we're at level 2, the key of this resource is the name
df3baf66 1494 we are going to use in the rc printout. */
252b5132
RH
1495 name = &re->id;
1496 break;
1497
1498 case 3:
1499 /* If we're at level 3, then this key represents a language.
1500 Use it to update the current language. */
1501 if (! re->id.named
1502 && re->id.u.id != (unsigned long) (unsigned int) *language
1503 && (re->id.u.id & 0xffff) == re->id.u.id)
1504 {
1505 fprintf (e, "LANGUAGE %lu, %lu\n",
53c7db4b 1506 re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
b24eb5ac 1507 (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
252b5132
RH
1508 *language = re->id.u.id;
1509 }
1510 break;
1511
1512 default:
1513 break;
1514 }
1515
1516 if (re->subdir)
1517 write_rc_subdir (e, re, type, name, language, level);
1518 else
1519 {
1520 if (level == 3)
1521 {
1522 /* This is the normal case: the three levels are
1523 TYPE/NAME/LANGUAGE. NAME will have been set at level
1524 2, and represents the name to use. We probably just
1525 set LANGUAGE, and it will probably match what the
1526 resource itself records if anything. */
1527 write_rc_resource (e, type, name, re->u.res, language);
1528 }
1529 else
1530 {
1531 fprintf (e, "// Resource at unexpected level %d\n", level);
1532 write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
1533 language);
1534 }
1535 }
1536 }
1537}
1538
1539/* Write out a subdirectory entry. E is the file to write to. RE is
1540 the subdirectory entry. TYPE and NAME are pointers to higher level
1541 IDs, or NULL. LANGUAGE is a pointer to the current language.
1542 LEVEL is the level in the tree. */
1543
1544static void
2da42df6
AJ
1545write_rc_subdir (FILE *e, const struct res_entry *re,
1546 const struct res_id *type, const struct res_id *name,
1547 int *language, int level)
252b5132
RH
1548{
1549 fprintf (e, "\n");
1550 switch (level)
1551 {
1552 case 1:
1553 fprintf (e, "// Type: ");
1554 if (re->id.named)
1555 res_id_print (e, re->id, 1);
1556 else
1557 {
1558 const char *s;
1559
1560 switch (re->id.u.id)
1561 {
1562 case RT_CURSOR: s = "cursor"; break;
1563 case RT_BITMAP: s = "bitmap"; break;
1564 case RT_ICON: s = "icon"; break;
1565 case RT_MENU: s = "menu"; break;
1566 case RT_DIALOG: s = "dialog"; break;
1567 case RT_STRING: s = "stringtable"; break;
1568 case RT_FONTDIR: s = "fontdir"; break;
1569 case RT_FONT: s = "font"; break;
1570 case RT_ACCELERATOR: s = "accelerators"; break;
1571 case RT_RCDATA: s = "rcdata"; break;
1572 case RT_MESSAGETABLE: s = "messagetable"; break;
1573 case RT_GROUP_CURSOR: s = "group cursor"; break;
1574 case RT_GROUP_ICON: s = "group icon"; break;
1575 case RT_VERSION: s = "version"; break;
1576 case RT_DLGINCLUDE: s = "dlginclude"; break;
1577 case RT_PLUGPLAY: s = "plugplay"; break;
1578 case RT_VXD: s = "vxd"; break;
1579 case RT_ANICURSOR: s = "anicursor"; break;
1580 case RT_ANIICON: s = "aniicon"; break;
1581 default: s = NULL; break;
1582 }
1583
1584 if (s != NULL)
1585 fprintf (e, "%s", s);
1586 else
1587 res_id_print (e, re->id, 1);
1588 }
1589 fprintf (e, "\n");
1590 break;
1591
1592 case 2:
1593 fprintf (e, "// Name: ");
1594 res_id_print (e, re->id, 1);
1595 fprintf (e, "\n");
1596 break;
1597
1598 case 3:
1599 fprintf (e, "// Language: ");
1600 res_id_print (e, re->id, 1);
1601 fprintf (e, "\n");
1602 break;
1603
1604 default:
1605 fprintf (e, "// Level %d: ", level);
1606 res_id_print (e, re->id, 1);
1607 fprintf (e, "\n");
53c7db4b 1608 }
252b5132
RH
1609
1610 write_rc_directory (e, re->u.dir, type, name, language, level + 1);
1611}
1612
1613/* Write out a single resource. E is the file to write to. TYPE is a
1614 pointer to the type of the resource. NAME is a pointer to the name
1615 of the resource; it will be NULL if there is a level mismatch. RES
1616 is the resource data. LANGUAGE is a pointer to the current
1617 language. */
1618
1619static void
2da42df6
AJ
1620write_rc_resource (FILE *e, const struct res_id *type,
1621 const struct res_id *name, const struct res_resource *res,
1622 int *language)
252b5132
RH
1623{
1624 const char *s;
1625 int rt;
1626 int menuex = 0;
1627
1628 fprintf (e, "\n");
1629
1630 switch (res->type)
1631 {
1632 default:
1633 abort ();
1634
1635 case RES_TYPE_ACCELERATOR:
1636 s = "ACCELERATOR";
1637 rt = RT_ACCELERATOR;
1638 break;
1639
1640 case RES_TYPE_BITMAP:
1641 s = "BITMAP";
1642 rt = RT_BITMAP;
1643 break;
1644
1645 case RES_TYPE_CURSOR:
1646 s = "CURSOR";
1647 rt = RT_CURSOR;
1648 break;
1649
1650 case RES_TYPE_GROUP_CURSOR:
1651 s = "GROUP_CURSOR";
1652 rt = RT_GROUP_CURSOR;
1653 break;
1654
1655 case RES_TYPE_DIALOG:
1656 if (extended_dialog (res->u.dialog))
1657 s = "DIALOGEX";
1658 else
1659 s = "DIALOG";
1660 rt = RT_DIALOG;
1661 break;
1662
1663 case RES_TYPE_FONT:
1664 s = "FONT";
1665 rt = RT_FONT;
1666 break;
1667
1668 case RES_TYPE_FONTDIR:
1669 s = "FONTDIR";
1670 rt = RT_FONTDIR;
1671 break;
1672
1673 case RES_TYPE_ICON:
1674 s = "ICON";
1675 rt = RT_ICON;
1676 break;
1677
1678 case RES_TYPE_GROUP_ICON:
1679 s = "GROUP_ICON";
1680 rt = RT_GROUP_ICON;
1681 break;
1682
1683 case RES_TYPE_MENU:
1684 if (extended_menu (res->u.menu))
1685 {
1686 s = "MENUEX";
1687 menuex = 1;
1688 }
1689 else
1690 {
1691 s = "MENU";
1692 menuex = 0;
1693 }
1694 rt = RT_MENU;
1695 break;
1696
1697 case RES_TYPE_MESSAGETABLE:
1698 s = "MESSAGETABLE";
1699 rt = RT_MESSAGETABLE;
1700 break;
1701
1702 case RES_TYPE_RCDATA:
1703 s = "RCDATA";
1704 rt = RT_RCDATA;
1705 break;
1706
1707 case RES_TYPE_STRINGTABLE:
1708 s = "STRINGTABLE";
1709 rt = RT_STRING;
1710 break;
1711
1712 case RES_TYPE_USERDATA:
1713 s = NULL;
1714 rt = 0;
1715 break;
1716
1717 case RES_TYPE_VERSIONINFO:
1718 s = "VERSIONINFO";
1719 rt = RT_VERSION;
1720 break;
1721 }
1722
1723 if (rt != 0
1724 && type != NULL
1725 && (type->named || type->u.id != (unsigned long) rt))
1726 {
1727 fprintf (e, "// Unexpected resource type mismatch: ");
1728 res_id_print (e, *type, 1);
1729 fprintf (e, " != %d", rt);
1730 }
1731
1732 if (res->coff_info.codepage != 0)
1733 fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
1734 if (res->coff_info.reserved != 0)
1735 fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
1736
1737 if (name != NULL)
1738 res_id_print (e, *name, 0);
1739 else
1740 fprintf (e, "??Unknown-Name??");
1741
1742 fprintf (e, " ");
1743 if (s != NULL)
1744 fprintf (e, "%s", s);
1745 else if (type != NULL)
1746 res_id_print (e, *type, 0);
1747 else
1748 fprintf (e, "??Unknown-Type??");
1749
1750 if (res->res_info.memflags != 0)
1751 {
1752 if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
1753 fprintf (e, " MOVEABLE");
1754 if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
1755 fprintf (e, " PURE");
1756 if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
1757 fprintf (e, " PRELOAD");
1758 if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
1759 fprintf (e, " DISCARDABLE");
1760 }
1761
1762 if (res->type == RES_TYPE_DIALOG)
1763 {
1764 fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
1765 res->u.dialog->width, res->u.dialog->height);
1766 if (res->u.dialog->ex != NULL
1767 && res->u.dialog->ex->help != 0)
1768 fprintf (e, ", %lu", res->u.dialog->ex->help);
1769 }
1770
1771 fprintf (e, "\n");
1772
1773 if ((res->res_info.language != 0 && res->res_info.language != *language)
1774 || res->res_info.characteristics != 0
1775 || res->res_info.version != 0)
1776 {
1777 int modifiers;
1778
1779 switch (res->type)
1780 {
1781 case RES_TYPE_ACCELERATOR:
1782 case RES_TYPE_DIALOG:
1783 case RES_TYPE_MENU:
1784 case RES_TYPE_RCDATA:
1785 case RES_TYPE_STRINGTABLE:
1786 modifiers = 1;
1787 break;
1788
1789 default:
1790 modifiers = 0;
1791 break;
1792 }
1793
1794 if (res->res_info.language != 0 && res->res_info.language != *language)
1795 fprintf (e, "%sLANGUAGE %d, %d\n",
1796 modifiers ? "// " : "",
95fd336c
DD
1797 res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
1798 (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
252b5132
RH
1799 if (res->res_info.characteristics != 0)
1800 fprintf (e, "%sCHARACTERISTICS %lu\n",
1801 modifiers ? "// " : "",
1802 res->res_info.characteristics);
1803 if (res->res_info.version != 0)
1804 fprintf (e, "%sVERSION %lu\n",
1805 modifiers ? "// " : "",
1806 res->res_info.version);
1807 }
1808
1809 switch (res->type)
1810 {
1811 default:
1812 abort ();
1813
1814 case RES_TYPE_ACCELERATOR:
1815 write_rc_accelerators (e, res->u.acc);
1816 break;
1817
1818 case RES_TYPE_CURSOR:
1819 write_rc_cursor (e, res->u.cursor);
1820 break;
1821
1822 case RES_TYPE_GROUP_CURSOR:
1823 write_rc_group_cursor (e, res->u.group_cursor);
1824 break;
1825
1826 case RES_TYPE_DIALOG:
1827 write_rc_dialog (e, res->u.dialog);
1828 break;
1829
1830 case RES_TYPE_FONTDIR:
1831 write_rc_fontdir (e, res->u.fontdir);
1832 break;
1833
1834 case RES_TYPE_GROUP_ICON:
1835 write_rc_group_icon (e, res->u.group_icon);
1836 break;
1837
1838 case RES_TYPE_MENU:
1839 write_rc_menu (e, res->u.menu, menuex);
1840 break;
1841
1842 case RES_TYPE_RCDATA:
1843 write_rc_rcdata (e, res->u.rcdata, 0);
1844 break;
1845
1846 case RES_TYPE_STRINGTABLE:
1847 write_rc_stringtable (e, name, res->u.stringtable);
1848 break;
1849
1850 case RES_TYPE_USERDATA:
1851 write_rc_rcdata (e, res->u.userdata, 0);
1852 break;
1853
1854 case RES_TYPE_VERSIONINFO:
1855 write_rc_versioninfo (e, res->u.versioninfo);
1856 break;
1857
1858 case RES_TYPE_BITMAP:
1859 case RES_TYPE_FONT:
1860 case RES_TYPE_ICON:
1861 case RES_TYPE_MESSAGETABLE:
1862 write_rc_filedata (e, res->u.data.length, res->u.data.data);
1863 break;
1864 }
1865}
1866
1867/* Write out accelerator information. */
1868
1869static void
2da42df6 1870write_rc_accelerators (FILE *e, const struct accelerator *accelerators)
252b5132
RH
1871{
1872 const struct accelerator *acc;
1873
1874 fprintf (e, "BEGIN\n");
1875 for (acc = accelerators; acc != NULL; acc = acc->next)
1876 {
1877 int printable;
1878
1879 fprintf (e, " ");
1880
1881 if ((acc->key & 0x7f) == acc->key
3882b010 1882 && ISPRINT (acc->key)
252b5132
RH
1883 && (acc->flags & ACC_VIRTKEY) == 0)
1884 {
1885 fprintf (e, "\"%c\"", acc->key);
1886 printable = 1;
1887 }
1888 else
1889 {
1890 fprintf (e, "%d", acc->key);
1891 printable = 0;
1892 }
1893
1894 fprintf (e, ", %d", acc->id);
1895
1896 if (! printable)
1897 {
1898 if ((acc->flags & ACC_VIRTKEY) != 0)
1899 fprintf (e, ", VIRTKEY");
1900 else
1901 fprintf (e, ", ASCII");
1902 }
1903
1904 if ((acc->flags & ACC_SHIFT) != 0)
1905 fprintf (e, ", SHIFT");
1906 if ((acc->flags & ACC_CONTROL) != 0)
1907 fprintf (e, ", CONTROL");
1908 if ((acc->flags & ACC_ALT) != 0)
1909 fprintf (e, ", ALT");
1910
1911 fprintf (e, "\n");
1912 }
1913
1914 fprintf (e, "END\n");
1915}
1916
1917/* Write out cursor information. This would normally be in a separate
1918 file, which the rc file would include. */
1919
1920static void
2da42df6 1921write_rc_cursor (FILE *e, const struct cursor *cursor)
252b5132
RH
1922{
1923 fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
1924 cursor->yhotspot);
1925 write_rc_filedata (e, cursor->length, cursor->data);
1926}
1927
1928/* Write out group cursor data. This would normally be built from the
1929 cursor data. */
1930
1931static void
2da42df6 1932write_rc_group_cursor (FILE *e, const struct group_cursor *group_cursor)
252b5132
RH
1933{
1934 const struct group_cursor *gc;
1935
1936 for (gc = group_cursor; gc != NULL; gc = gc->next)
1937 {
1938 fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
1939 gc->width, gc->height, gc->planes, gc->bits);
1940 fprintf (e, "// data bytes: %lu; index: %d\n",
1941 gc->bytes, gc->index);
1942 }
1943}
1944
1945/* Write dialog data. */
1946
1947static void
2da42df6 1948write_rc_dialog (FILE *e, const struct dialog *dialog)
252b5132
RH
1949{
1950 const struct dialog_control *control;
1951
91eafb40
NC
1952 fprintf (e, "STYLE 0x%lx\n", dialog->style);
1953
252b5132
RH
1954 if (dialog->exstyle != 0)
1955 fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
91eafb40 1956
252b5132
RH
1957 if ((dialog->class.named && dialog->class.u.n.length > 0)
1958 || dialog->class.u.id != 0)
1959 {
1960 fprintf (e, "CLASS ");
df3baf66 1961 res_id_print (e, dialog->class, 1);
252b5132
RH
1962 fprintf (e, "\n");
1963 }
91eafb40 1964
252b5132
RH
1965 if (dialog->caption != NULL)
1966 {
1967 fprintf (e, "CAPTION \"");
1968 unicode_print (e, dialog->caption, -1);
1969 fprintf (e, "\"\n");
1970 }
91eafb40 1971
252b5132
RH
1972 if ((dialog->menu.named && dialog->menu.u.n.length > 0)
1973 || dialog->menu.u.id != 0)
1974 {
1975 fprintf (e, "MENU ");
1976 res_id_print (e, dialog->menu, 0);
1977 fprintf (e, "\n");
1978 }
91eafb40 1979
252b5132
RH
1980 if (dialog->font != NULL)
1981 {
1982 fprintf (e, "FONT %d, \"", dialog->pointsize);
1983 unicode_print (e, dialog->font, -1);
1984 fprintf (e, "\"");
1985 if (dialog->ex != NULL
45b99827
NC
1986 && (dialog->ex->weight != 0
1987 || dialog->ex->italic != 0
1988 || dialog->ex->charset != 1))
1989 fprintf (e, ", %d, %d, %d",
1990 dialog->ex->weight, dialog->ex->italic, dialog->ex->charset);
252b5132
RH
1991 fprintf (e, "\n");
1992 }
1993
1994 fprintf (e, "BEGIN\n");
1995
1996 for (control = dialog->controls; control != NULL; control = control->next)
1997 write_rc_dialog_control (e, control);
1998
1999 fprintf (e, "END\n");
2000}
2001
2002/* For each predefined control keyword, this table provides the class
2003 and the style. */
2004
2005struct control_info
2006{
2007 const char *name;
2008 unsigned short class;
2009 unsigned long style;
2010};
2011
2012static const struct control_info control_info[] =
2013{
2014 { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2015 { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2016 { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2017 { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2018 { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2019 { "CTEXT", CTL_STATIC, SS_CENTER },
2020 { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2021 { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2022 { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2023 { "ICON", CTL_STATIC, SS_ICON },
2024 { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2025 { "LTEXT", CTL_STATIC, SS_LEFT },
2026 { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2027 { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2028 { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2029 { "RTEXT", CTL_STATIC, SS_RIGHT },
2030 { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2031 { "STATE3", CTL_BUTTON, BS_3STATE },
2032 /* It's important that USERBUTTON come after all the other button
2033 types, so that it won't be matched too early. */
2034 { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2035 { NULL, 0, 0 }
2036};
2037
2038/* Write a dialog control. */
2039
2040static void
2da42df6 2041write_rc_dialog_control (FILE *e, const struct dialog_control *control)
252b5132
RH
2042{
2043 const struct control_info *ci;
2044
2045 fprintf (e, " ");
2046
2047 if (control->class.named)
2048 ci = NULL;
2049 else
2050 {
2051 for (ci = control_info; ci->name != NULL; ++ci)
2052 if (ci->class == control->class.u.id
2053 && (ci->style == (unsigned long) -1
2054 || ci->style == (control->style & 0xff)))
2055 break;
2056 }
2057 if (ci == NULL)
2058 fprintf (e, "CONTROL");
2059 else if (ci->name != NULL)
2060 fprintf (e, "%s", ci->name);
2061 else
2062 fprintf (e, "CONTROL");
53c7db4b 2063
252b5132
RH
2064 if (control->text.named || control->text.u.id != 0)
2065 {
2066 fprintf (e, " ");
2067 res_id_print (e, control->text, 1);
2068 fprintf (e, ",");
2069 }
2070
2071 fprintf (e, " %d, ", control->id);
2072
2073 if (ci == NULL)
2074 {
2075 if (control->class.named)
2076 fprintf (e, "\"");
2077 res_id_print (e, control->class, 0);
2078 if (control->class.named)
2079 fprintf (e, "\"");
2080 fprintf (e, ", 0x%lx, ", control->style);
2081 }
2082
2083 fprintf (e, "%d, %d", control->x, control->y);
2084
2085 if (control->style != SS_ICON
2086 || control->exstyle != 0
2087 || control->width != 0
2088 || control->height != 0
2089 || control->help != 0)
2090 {
2091 fprintf (e, ", %d, %d", control->width, control->height);
2092
2093 /* FIXME: We don't need to print the style if it is the default.
2094 More importantly, in certain cases we actually need to turn
2095 off parts of the forced style, by using NOT. */
2096 fprintf (e, ", 0x%lx", control->style);
2097
2098 if (control->exstyle != 0 || control->help != 0)
2099 fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
2100 }
2101
2102 fprintf (e, "\n");
2103
2104 if (control->data != NULL)
2105 write_rc_rcdata (e, control->data, 2);
2106}
2107
2108/* Write out font directory data. This would normally be built from
2109 the font data. */
2110
2111static void
2da42df6 2112write_rc_fontdir (FILE *e, const struct fontdir *fontdir)
252b5132
RH
2113{
2114 const struct fontdir *fc;
2115
2116 for (fc = fontdir; fc != NULL; fc = fc->next)
2117 {
2118 fprintf (e, "// Font index: %d\n", fc->index);
2119 write_rc_filedata (e, fc->length, fc->data);
2120 }
2121}
2122
2123/* Write out group icon data. This would normally be built from the
2124 icon data. */
2125
2126static void
2da42df6 2127write_rc_group_icon (FILE *e, const struct group_icon *group_icon)
252b5132
RH
2128{
2129 const struct group_icon *gi;
2130
2131 for (gi = group_icon; gi != NULL; gi = gi->next)
2132 {
2133 fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
2134 gi->width, gi->height, gi->colors, gi->planes, gi->bits);
2135 fprintf (e, "// data bytes: %lu; index: %d\n",
2136 gi->bytes, gi->index);
2137 }
2138}
2139
2140/* Write out a menu resource. */
2141
2142static void
2da42df6 2143write_rc_menu (FILE *e, const struct menu *menu, int menuex)
252b5132
RH
2144{
2145 if (menu->help != 0)
2146 fprintf (e, "// Help ID: %lu\n", menu->help);
2147 write_rc_menuitems (e, menu->items, menuex, 0);
2148}
2149
2150/* Write out menuitems. */
2151
2152static void
2da42df6
AJ
2153write_rc_menuitems (FILE *e, const struct menuitem *menuitems, int menuex,
2154 int ind)
252b5132
RH
2155{
2156 const struct menuitem *mi;
2157
2158 indent (e, ind);
2159 fprintf (e, "BEGIN\n");
2160
2161 for (mi = menuitems; mi != NULL; mi = mi->next)
2162 {
2163 indent (e, ind + 2);
2164
2165 if (mi->popup == NULL)
2166 fprintf (e, "MENUITEM");
2167 else
2168 fprintf (e, "POPUP");
2169
2170 if (! menuex
2171 && mi->popup == NULL
2172 && mi->text == NULL
2173 && mi->type == 0
2174 && mi->id == 0)
2175 {
2176 fprintf (e, " SEPARATOR\n");
2177 continue;
2178 }
2179
2180 if (mi->text == NULL)
2181 fprintf (e, " \"\"");
2182 else
2183 {
2184 fprintf (e, " \"");
2185 unicode_print (e, mi->text, -1);
2186 fprintf (e, "\"");
2187 }
2188
2189 if (! menuex)
2190 {
2191 if (mi->popup == NULL)
2192 fprintf (e, ", %d", mi->id);
2193
2194 if ((mi->type & MENUITEM_CHECKED) != 0)
2195 fprintf (e, ", CHECKED");
2196 if ((mi->type & MENUITEM_GRAYED) != 0)
2197 fprintf (e, ", GRAYED");
2198 if ((mi->type & MENUITEM_HELP) != 0)
2199 fprintf (e, ", HELP");
2200 if ((mi->type & MENUITEM_INACTIVE) != 0)
2201 fprintf (e, ", INACTIVE");
2202 if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2203 fprintf (e, ", MENUBARBREAK");
2204 if ((mi->type & MENUITEM_MENUBREAK) != 0)
2205 fprintf (e, ", MENUBREAK");
2206 }
2207 else
2208 {
2209 if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2210 {
2211 fprintf (e, ", %d", mi->id);
2212 if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2213 {
2214 fprintf (e, ", %lu", mi->type);
2215 if (mi->state != 0 || mi->help != 0)
2216 {
2217 fprintf (e, ", %lu", mi->state);
2218 if (mi->help != 0)
2219 fprintf (e, ", %lu", mi->help);
2220 }
2221 }
2222 }
2223 }
2224
2225 fprintf (e, "\n");
2226
2227 if (mi->popup != NULL)
2228 write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2229 }
2230
2231 indent (e, ind);
2232 fprintf (e, "END\n");
2233}
2234
2235/* Write out an rcdata resource. This is also used for other types of
2236 resources that need to print arbitrary data. */
2237
2238static void
2da42df6 2239write_rc_rcdata (FILE *e, const struct rcdata_item *rcdata, int ind)
252b5132
RH
2240{
2241 const struct rcdata_item *ri;
2242
2243 indent (e, ind);
2244 fprintf (e, "BEGIN\n");
2245
2246 for (ri = rcdata; ri != NULL; ri = ri->next)
2247 {
2248 if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
2249 continue;
2250
2251 indent (e, ind + 2);
2252
2253 switch (ri->type)
2254 {
2255 default:
2256 abort ();
2257
2258 case RCDATA_WORD:
2259 fprintf (e, "%d", ri->u.word);
2260 break;
2261
2262 case RCDATA_DWORD:
2263 fprintf (e, "%luL", ri->u.dword);
2264 break;
2265
2266 case RCDATA_STRING:
2267 {
2268 const char *s;
2269 unsigned long i;
2270
2271 fprintf (e, "\"");
2272 s = ri->u.string.s;
2273 for (i = 0; i < ri->u.string.length; i++)
2274 {
3882b010 2275 if (ISPRINT (*s))
252b5132
RH
2276 putc (*s, e);
2277 else
2278 fprintf (e, "\\%03o", *s);
2279 }
2280 fprintf (e, "\"");
2281 break;
2282 }
2283
2284 case RCDATA_WSTRING:
2285 fprintf (e, "L\"");
2286 unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
2287 fprintf (e, "\"");
2288 break;
2289
2290 case RCDATA_BUFFER:
2291 {
2292 unsigned long i;
2293 int first;
2294
2295 /* Assume little endian data. */
2296
2297 first = 1;
2298 for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
2299 {
2300 unsigned long l;
34ca6cf8 2301 int j;
252b5132 2302
34ca6cf8
ILT
2303 if (! first)
2304 indent (e, ind + 2);
252b5132
RH
2305 l = ((((((ri->u.buffer.data[i + 3] << 8)
2306 | ri->u.buffer.data[i + 2]) << 8)
2307 | ri->u.buffer.data[i + 1]) << 8)
2308 | ri->u.buffer.data[i]);
34ca6cf8
ILT
2309 fprintf (e, "%luL", l);
2310 if (i + 4 < ri->u.buffer.length || ri->next != NULL)
2311 fprintf (e, ",");
2312 for (j = 0; j < 4; ++j)
3882b010 2313 if (! ISPRINT (ri->u.buffer.data[i + j])
34ca6cf8
ILT
2314 && ri->u.buffer.data[i + j] != 0)
2315 break;
2316 if (j >= 4)
252b5132 2317 {
34ca6cf8
ILT
2318 fprintf (e, "\t// ");
2319 for (j = 0; j < 4; ++j)
2320 {
3882b010 2321 if (! ISPRINT (ri->u.buffer.data[i + j]))
34ca6cf8
ILT
2322 fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2323 else
2324 {
2325 if (ri->u.buffer.data[i + j] == '\\')
2326 fprintf (e, "\\");
2327 fprintf (e, "%c", ri->u.buffer.data[i + j]);
2328 }
2329 }
252b5132 2330 }
34ca6cf8
ILT
2331 fprintf (e, "\n");
2332 first = 0;
252b5132
RH
2333 }
2334
2335 if (i + 1 < ri->u.buffer.length)
2336 {
34ca6cf8
ILT
2337 int s;
2338 int j;
2339
2340 if (! first)
2341 indent (e, ind + 2);
2342 s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
2343 fprintf (e, "%d", s);
2344 if (i + 2 < ri->u.buffer.length || ri->next != NULL)
2345 fprintf (e, ",");
2346 for (j = 0; j < 2; ++j)
3882b010 2347 if (! ISPRINT (ri->u.buffer.data[i + j])
34ca6cf8
ILT
2348 && ri->u.buffer.data[i + j] != 0)
2349 break;
2350 if (j >= 2)
252b5132 2351 {
34ca6cf8
ILT
2352 fprintf (e, "\t// ");
2353 for (j = 0; j < 2; ++j)
2354 {
3882b010 2355 if (! ISPRINT (ri->u.buffer.data[i + j]))
34ca6cf8
ILT
2356 fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2357 else
2358 {
2359 if (ri->u.buffer.data[i + j] == '\\')
2360 fprintf (e, "\\");
2361 fprintf (e, "%c", ri->u.buffer.data[i + j]);
2362 }
2363 }
252b5132 2364 }
34ca6cf8 2365 fprintf (e, "\n");
252b5132 2366 i += 2;
34ca6cf8 2367 first = 0;
252b5132
RH
2368 }
2369
2370 if (i < ri->u.buffer.length)
2371 {
34ca6cf8
ILT
2372 if (! first)
2373 indent (e, ind + 2);
252b5132 2374 if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
3882b010 2375 && ISPRINT (ri->u.buffer.data[i]))
252b5132
RH
2376 fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
2377 else
34ca6cf8
ILT
2378 fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
2379 if (ri->next != NULL)
2380 fprintf (e, ",");
2381 fprintf (e, "\n");
2382 first = 0;
252b5132
RH
2383 }
2384
2385 break;
2386 }
2387 }
2388
34ca6cf8
ILT
2389 if (ri->type != RCDATA_BUFFER)
2390 {
2391 if (ri->next != NULL)
2392 fprintf (e, ",");
2393 fprintf (e, "\n");
2394 }
252b5132
RH
2395 }
2396
2397 indent (e, ind);
2398 fprintf (e, "END\n");
2399}
2400
2401/* Write out a stringtable resource. */
2402
2403static void
2da42df6
AJ
2404write_rc_stringtable (FILE *e, const struct res_id *name,
2405 const struct stringtable *stringtable)
252b5132
RH
2406{
2407 unsigned long offset;
2408 int i;
2409
2410 if (name != NULL && ! name->named)
2411 offset = (name->u.id - 1) << 4;
2412 else
2413 {
2414 fprintf (e, "// %s string table name\n",
2415 name == NULL ? "Missing" : "Invalid");
2416 offset = 0;
2417 }
2418
2419 fprintf (e, "BEGIN\n");
2420
2421 for (i = 0; i < 16; i++)
2422 {
2423 if (stringtable->strings[i].length != 0)
2424 {
2425 fprintf (e, " %lu, \"", offset + i);
2426 unicode_print (e, stringtable->strings[i].string,
2427 stringtable->strings[i].length);
2428 fprintf (e, "\"\n");
2429 }
2430 }
2431
2432 fprintf (e, "END\n");
2433}
2434
2435/* Write out a versioninfo resource. */
2436
2437static void
2da42df6 2438write_rc_versioninfo (FILE *e, const struct versioninfo *versioninfo)
252b5132
RH
2439{
2440 const struct fixed_versioninfo *f;
2441 const struct ver_info *vi;
2442
2443 f = versioninfo->fixed;
2444 if (f->file_version_ms != 0 || f->file_version_ls != 0)
2445 fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
2446 (f->file_version_ms >> 16) & 0xffff,
2447 f->file_version_ms & 0xffff,
2448 (f->file_version_ls >> 16) & 0xffff,
2449 f->file_version_ls & 0xffff);
2450 if (f->product_version_ms != 0 || f->product_version_ls != 0)
2451 fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
2452 (f->product_version_ms >> 16) & 0xffff,
2453 f->product_version_ms & 0xffff,
2454 (f->product_version_ls >> 16) & 0xffff,
2455 f->product_version_ls & 0xffff);
2456 if (f->file_flags_mask != 0)
2457 fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
2458 if (f->file_flags != 0)
2459 fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
2460 if (f->file_os != 0)
2461 fprintf (e, " FILEOS 0x%lx\n", f->file_os);
2462 if (f->file_type != 0)
2463 fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
2464 if (f->file_subtype != 0)
2465 fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
2466 if (f->file_date_ms != 0 || f->file_date_ls != 0)
2467 fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
2468
2469 fprintf (e, "BEGIN\n");
2470
2471 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2472 {
2473 switch (vi->type)
2474 {
2475 case VERINFO_STRING:
2476 {
2477 const struct ver_stringinfo *vs;
2478
2479 fprintf (e, " BLOCK \"StringFileInfo\"\n");
2480 fprintf (e, " BEGIN\n");
2481 fprintf (e, " BLOCK \"");
2482 unicode_print (e, vi->u.string.language, -1);
2483 fprintf (e, "\"\n");
2484 fprintf (e, " BEGIN\n");
2485
2486 for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2487 {
2488 fprintf (e, " VALUE \"");
2489 unicode_print (e, vs->key, -1);
2490 fprintf (e, "\", \"");
2491 unicode_print (e, vs->value, -1);
2492 fprintf (e, "\"\n");
2493 }
2494
2495 fprintf (e, " END\n");
2496 fprintf (e, " END\n");
2497 break;
2498 }
2499
2500 case VERINFO_VAR:
2501 {
2502 const struct ver_varinfo *vv;
2503
2504 fprintf (e, " BLOCK \"VarFileInfo\"\n");
2505 fprintf (e, " BEGIN\n");
2506 fprintf (e, " VALUE \"");
2507 unicode_print (e, vi->u.var.key, -1);
2508 fprintf (e, "\"");
2509
2510 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2511 fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
2512 vv->charset);
2513
2514 fprintf (e, "\n END\n");
2515
2516 break;
2517 }
2518 }
2519 }
2520
2521 fprintf (e, "END\n");
2522}
2523
2524/* Write out data which would normally be read from a file. */
2525
2526static void
2da42df6 2527write_rc_filedata (FILE *e, unsigned long length, const unsigned char *data)
252b5132
RH
2528{
2529 unsigned long i;
2530
2531 for (i = 0; i + 15 < length; i += 16)
2532 {
2533 fprintf (e, "// %4lx: ", i);
2534 fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
2535 data[i + 0], data[i + 1], data[i + 2], data[i + 3],
2536 data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
2537 fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2538 data[i + 8], data[i + 9], data[i + 10], data[i + 11],
2539 data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
2540 }
2541
2542 if (i < length)
2543 {
2544 fprintf (e, "// %4lx:", i);
2545 while (i < length)
2546 {
2547 fprintf (e, " %02x", data[i]);
2548 ++i;
2549 }
2550 fprintf (e, "\n");
2551 }
2552}
This page took 0.325047 seconds and 4 git commands to generate.