* Makefile.am: Add LIBICONV to windres.
[deliverable/binutils-gdb.git] / binutils / windres.c
CommitLineData
252b5132 1/* windres.c -- a program to manipulate Windows resources
92f01d61 2 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
29b058f1 3 Free Software Foundation, Inc.
252b5132 4 Written by Ian Lance Taylor, Cygnus Support.
4a594fce 5 Rewritten by Kai Tietz, Onevision.
252b5132
RH
6
7 This file is part of GNU Binutils.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
b43b5d5f
NC
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
252b5132
RH
23
24/* This program can read and write Windows resources in various
25 formats. In particular, it can act like the rc resource compiler
26 program, and it can act like the cvtres res to COFF conversion
27 program.
28
29 It is based on information taken from the following sources:
30
31 * Microsoft documentation.
32
33 * The rcl program, written by Gunther Ebert
34 <gunther.ebert@ixos-leipzig.de>.
35
29b058f1 36 * The res2coff program, written by Pedro A. Aranda <paag@tid.es>. */
252b5132 37
3db64b00 38#include "sysdep.h"
0af6db78
AM
39#include <assert.h>
40#include <time.h>
252b5132
RH
41#include "bfd.h"
42#include "getopt.h"
4a594fce 43#include "bucomm.h"
252b5132 44#include "libiberty.h"
3882b010 45#include "safe-ctype.h"
252b5132
RH
46#include "obstack.h"
47#include "windres.h"
252b5132 48
4a594fce
NC
49/* Defined in bfd/binary.c. Used to set architecture and machine of input
50 binary files. */
51extern enum bfd_architecture bfd_external_binary_architecture;
52extern unsigned long bfd_external_machine;
53
29b058f1 54/* Used by resrc.c at least. */
751d21b5
DD
55
56int verbose = 0;
57
4a594fce
NC
58int target_is_bigendian = 0;
59const char *def_target_arch;
60
61static void set_endianess (bfd *, const char *);
62
252b5132
RH
63/* An enumeration of format types. */
64
65enum res_format
66{
67 /* Unknown format. */
68 RES_FORMAT_UNKNOWN,
69 /* Textual RC file. */
70 RES_FORMAT_RC,
71 /* Binary RES file. */
72 RES_FORMAT_RES,
73 /* COFF file. */
74 RES_FORMAT_COFF
75};
76
77/* A structure used to map between format types and strings. */
78
79struct format_map
80{
81 const char *name;
82 enum res_format format;
83};
84
85/* A mapping between names and format types. */
86
87static const struct format_map format_names[] =
88{
89 { "rc", RES_FORMAT_RC },
90 { "res", RES_FORMAT_RES },
91 { "coff", RES_FORMAT_COFF },
92 { NULL, RES_FORMAT_UNKNOWN }
93};
94
95/* A mapping from file extensions to format types. */
96
97static const struct format_map format_fileexts[] =
98{
99 { "rc", RES_FORMAT_RC },
100 { "res", RES_FORMAT_RES },
101 { "exe", RES_FORMAT_COFF },
102 { "obj", RES_FORMAT_COFF },
103 { "o", RES_FORMAT_COFF },
104 { NULL, RES_FORMAT_UNKNOWN }
105};
106
107/* A list of include directories. */
108
109struct include_dir
110{
111 struct include_dir *next;
112 char *dir;
113};
114
115static struct include_dir *include_dirs;
116
252b5132
RH
117/* Static functions. */
118
2da42df6 119static void res_init (void);
4a594fce 120static int extended_menuitems (const rc_menuitem *);
2da42df6
AJ
121static enum res_format format_from_name (const char *, int);
122static enum res_format format_from_filename (const char *, int);
123static void usage (FILE *, int);
124static int cmp_res_entry (const void *, const void *);
4a594fce 125static rc_res_directory *sort_resources (rc_res_directory *);
2da42df6
AJ
126static void reswr_init (void);
127static const char * quot (const char *);
4a594fce
NC
128\f
129static rc_uint_type target_get_8 (const void *, rc_uint_type);
130static void target_put_8 (void *, rc_uint_type);
131static rc_uint_type target_get_16 (const void *, rc_uint_type);
132static void target_put_16 (void *, rc_uint_type);
133static rc_uint_type target_get_32 (const void *, rc_uint_type);
134static void target_put_32 (void *, rc_uint_type);
135
252b5132
RH
136\f
137/* When we are building a resource tree, we allocate everything onto
138 an obstack, so that we can free it all at once if we want. */
139
140#define obstack_chunk_alloc xmalloc
141#define obstack_chunk_free free
142
143/* The resource building obstack. */
144
145static struct obstack res_obstack;
146
147/* Initialize the resource building obstack. */
148
149static void
2da42df6 150res_init (void)
252b5132
RH
151{
152 obstack_init (&res_obstack);
153}
154
155/* Allocate space on the resource building obstack. */
156
2da42df6 157void *
4a594fce 158res_alloc (rc_uint_type bytes)
252b5132 159{
4a594fce 160 return (void *) obstack_alloc (&res_obstack, (size_t) bytes);
252b5132
RH
161}
162
163/* We also use an obstack to save memory used while writing out a set
164 of resources. */
165
166static struct obstack reswr_obstack;
167
168/* Initialize the resource writing obstack. */
169
170static void
2da42df6 171reswr_init (void)
252b5132
RH
172{
173 obstack_init (&reswr_obstack);
174}
175
176/* Allocate space on the resource writing obstack. */
177
2da42df6 178void *
4a594fce 179reswr_alloc (rc_uint_type bytes)
252b5132 180{
4a594fce 181 return (void *) obstack_alloc (&reswr_obstack, (size_t) bytes);
252b5132
RH
182}
183\f
184/* Open a file using the include directory search list. */
185
186FILE *
2da42df6
AJ
187open_file_search (const char *filename, const char *mode, const char *errmsg,
188 char **real_filename)
252b5132
RH
189{
190 FILE *e;
191 struct include_dir *d;
192
193 e = fopen (filename, mode);
194 if (e != NULL)
195 {
196 *real_filename = xstrdup (filename);
197 return e;
198 }
199
200 if (errno == ENOENT)
201 {
202 for (d = include_dirs; d != NULL; d = d->next)
203 {
204 char *n;
205
206 n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
207 sprintf (n, "%s/%s", d->dir, filename);
208 e = fopen (n, mode);
209 if (e != NULL)
210 {
211 *real_filename = n;
212 return e;
213 }
214
215 if (errno != ENOENT)
216 break;
217 }
218 }
219
220 fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
221
222 /* Return a value to avoid a compiler warning. */
223 return NULL;
224}
225\f
226/* Compare two resource ID's. We consider name entries to come before
227 numeric entries, because that is how they appear in the COFF .rsrc
228 section. */
229
230int
4a594fce 231res_id_cmp (rc_res_id a, rc_res_id b)
252b5132
RH
232{
233 if (! a.named)
234 {
235 if (b.named)
236 return 1;
237 if (a.u.id > b.u.id)
238 return 1;
239 else if (a.u.id < b.u.id)
240 return -1;
241 else
242 return 0;
243 }
244 else
245 {
246 unichar *as, *ase, *bs, *bse;
247
248 if (! b.named)
249 return -1;
250
251 as = a.u.n.name;
252 ase = as + a.u.n.length;
253 bs = b.u.n.name;
254 bse = bs + b.u.n.length;
255
256 while (as < ase)
257 {
258 int i;
259
260 if (bs >= bse)
261 return 1;
262 i = (int) *as - (int) *bs;
263 if (i != 0)
264 return i;
265 ++as;
266 ++bs;
267 }
268
269 if (bs < bse)
270 return -1;
271
272 return 0;
273 }
274}
275
276/* Print a resource ID. */
277
278void
4a594fce 279res_id_print (FILE *stream, rc_res_id id, int quote)
252b5132
RH
280{
281 if (! id.named)
4a594fce 282 fprintf (stream, "%u", (int) id.u.id);
252b5132
RH
283 else
284 {
285 if (quote)
4a594fce
NC
286 unicode_print_quoted (stream, id.u.n.name, id.u.n.length);
287 else
252b5132 288 unicode_print (stream, id.u.n.name, id.u.n.length);
252b5132
RH
289 }
290}
291
292/* Print a list of resource ID's. */
293
294void
4a594fce 295res_ids_print (FILE *stream, int cids, const rc_res_id *ids)
252b5132
RH
296{
297 int i;
298
299 for (i = 0; i < cids; i++)
300 {
301 res_id_print (stream, ids[i], 1);
302 if (i + 1 < cids)
303 fprintf (stream, ": ");
304 }
305}
306
307/* Convert an ASCII string to a resource ID. */
308
309void
4a594fce 310res_string_to_id (rc_res_id *res_id, const char *string)
252b5132
RH
311{
312 res_id->named = 1;
313 unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
314}
315
4a594fce
NC
316/* Convert an unicode string to a resource ID. */
317void
318res_unistring_to_id (rc_res_id *res_id, const unichar *u)
319{
320 res_id->named = 1;
321 res_id->u.n.length = unichar_len (u);
322 res_id->u.n.name = unichar_dup_uppercase (u);
323}
324
252b5132
RH
325/* Define a resource. The arguments are the resource tree, RESOURCES,
326 and the location at which to put it in the tree, CIDS and IDS.
4a594fce 327 This returns a newly allocated rc_res_resource structure, which the
252b5132
RH
328 caller is expected to initialize. If DUPOK is non-zero, then if a
329 resource with this ID exists, it is returned. Otherwise, a warning
330 is issued, and a new resource is created replacing the existing
331 one. */
332
4a594fce
NC
333rc_res_resource *
334define_resource (rc_res_directory **resources, int cids,
335 const rc_res_id *ids, int dupok)
252b5132 336{
4a594fce 337 rc_res_entry *re = NULL;
252b5132
RH
338 int i;
339
340 assert (cids > 0);
341 for (i = 0; i < cids; i++)
342 {
4a594fce 343 rc_res_entry **pp;
252b5132
RH
344
345 if (*resources == NULL)
346 {
4a594fce 347 static unsigned int timeval;
252b5132
RH
348
349 /* Use the same timestamp for every resource created in a
350 single run. */
351 if (timeval == 0)
352 timeval = time (NULL);
353
4a594fce
NC
354 *resources = ((rc_res_directory *)
355 res_alloc (sizeof (rc_res_directory)));
252b5132
RH
356 (*resources)->characteristics = 0;
357 (*resources)->time = timeval;
358 (*resources)->major = 0;
359 (*resources)->minor = 0;
360 (*resources)->entries = NULL;
361 }
362
363 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
364 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
365 break;
366
367 if (*pp != NULL)
368 re = *pp;
369 else
370 {
4a594fce 371 re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry));
252b5132
RH
372 re->next = NULL;
373 re->id = ids[i];
374 if ((i + 1) < cids)
375 {
376 re->subdir = 1;
377 re->u.dir = NULL;
378 }
379 else
380 {
381 re->subdir = 0;
382 re->u.res = NULL;
383 }
384
385 *pp = re;
386 }
387
388 if ((i + 1) < cids)
389 {
390 if (! re->subdir)
391 {
392 fprintf (stderr, "%s: ", program_name);
393 res_ids_print (stderr, i, ids);
394 fprintf (stderr, _(": expected to be a directory\n"));
395 xexit (1);
396 }
397
398 resources = &re->u.dir;
399 }
400 }
401
402 if (re->subdir)
403 {
404 fprintf (stderr, "%s: ", program_name);
405 res_ids_print (stderr, cids, ids);
406 fprintf (stderr, _(": expected to be a leaf\n"));
407 xexit (1);
408 }
409
410 if (re->u.res != NULL)
411 {
412 if (dupok)
413 return re->u.res;
414
415 fprintf (stderr, _("%s: warning: "), program_name);
416 res_ids_print (stderr, cids, ids);
417 fprintf (stderr, _(": duplicate value\n"));
418 }
419
4a594fce
NC
420 re->u.res = ((rc_res_resource *)
421 res_alloc (sizeof (rc_res_resource)));
422 memset (re->u.res, 0, sizeof (rc_res_resource));
252b5132
RH
423
424 re->u.res->type = RES_TYPE_UNINITIALIZED;
252b5132
RH
425 return re->u.res;
426}
427
428/* Define a standard resource. This is a version of define_resource
429 that just takes type, name, and language arguments. */
430
4a594fce
NC
431rc_res_resource *
432define_standard_resource (rc_res_directory **resources, int type,
433 rc_res_id name, rc_uint_type language, int dupok)
252b5132 434{
4a594fce 435 rc_res_id a[3];
252b5132
RH
436
437 a[0].named = 0;
438 a[0].u.id = type;
439 a[1] = name;
440 a[2].named = 0;
441 a[2].u.id = language;
442 return define_resource (resources, 3, a, dupok);
443}
444
445/* Comparison routine for resource sorting. */
446
447static int
2da42df6 448cmp_res_entry (const void *p1, const void *p2)
252b5132 449{
4a594fce 450 const rc_res_entry **re1, **re2;
252b5132 451
4a594fce
NC
452 re1 = (const rc_res_entry **) p1;
453 re2 = (const rc_res_entry **) p2;
252b5132
RH
454 return res_id_cmp ((*re1)->id, (*re2)->id);
455}
456
457/* Sort the resources. */
458
4a594fce
NC
459static rc_res_directory *
460sort_resources (rc_res_directory *resdir)
252b5132
RH
461{
462 int c, i;
4a594fce
NC
463 rc_res_entry *re;
464 rc_res_entry **a;
252b5132
RH
465
466 if (resdir->entries == NULL)
467 return resdir;
468
469 c = 0;
470 for (re = resdir->entries; re != NULL; re = re->next)
471 ++c;
472
473 /* This is a recursive routine, so using xmalloc is probably better
474 than alloca. */
4a594fce 475 a = (rc_res_entry **) xmalloc (c * sizeof (rc_res_entry *));
252b5132
RH
476
477 for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
478 a[i] = re;
479
4a594fce 480 qsort (a, c, sizeof (rc_res_entry *), cmp_res_entry);
252b5132
RH
481
482 resdir->entries = a[0];
483 for (i = 0; i < c - 1; i++)
484 a[i]->next = a[i + 1];
485 a[i]->next = NULL;
486
487 free (a);
488
489 /* Now sort the subdirectories. */
490
491 for (re = resdir->entries; re != NULL; re = re->next)
492 if (re->subdir)
493 re->u.dir = sort_resources (re->u.dir);
494
495 return resdir;
496}
497\f
498/* Return whether the dialog resource DIALOG is a DIALOG or a
499 DIALOGEX. */
500
501int
4a594fce 502extended_dialog (const rc_dialog *dialog)
252b5132 503{
4a594fce 504 const rc_dialog_control *c;
252b5132
RH
505
506 if (dialog->ex != NULL)
507 return 1;
508
509 for (c = dialog->controls; c != NULL; c = c->next)
510 if (c->data != NULL || c->help != 0)
511 return 1;
512
513 return 0;
514}
515
516/* Return whether MENUITEMS are a MENU or a MENUEX. */
517
518int
4a594fce 519extended_menu (const rc_menu *menu)
252b5132
RH
520{
521 return extended_menuitems (menu->items);
522}
523
524static int
4a594fce 525extended_menuitems (const rc_menuitem *menuitems)
252b5132 526{
4a594fce 527 const rc_menuitem *mi;
252b5132
RH
528
529 for (mi = menuitems; mi != NULL; mi = mi->next)
530 {
531 if (mi->help != 0 || mi->state != 0)
532 return 1;
533 if (mi->popup != NULL && mi->id != 0)
534 return 1;
535 if ((mi->type
536 & ~ (MENUITEM_CHECKED
537 | MENUITEM_GRAYED
538 | MENUITEM_HELP
539 | MENUITEM_INACTIVE
540 | MENUITEM_MENUBARBREAK
541 | MENUITEM_MENUBREAK))
542 != 0)
543 return 1;
544 if (mi->popup != NULL)
545 {
546 if (extended_menuitems (mi->popup))
547 return 1;
548 }
549 }
550
551 return 0;
552}
553\f
554/* Convert a string to a format type, or exit if it can't be done. */
555
556static enum res_format
2da42df6 557format_from_name (const char *name, int exit_on_error)
252b5132
RH
558{
559 const struct format_map *m;
560
561 for (m = format_names; m->name != NULL; m++)
562 if (strcasecmp (m->name, name) == 0)
563 break;
564
85eb5110 565 if (m->name == NULL && exit_on_error)
252b5132 566 {
37cc8ec1 567 non_fatal (_("unknown format type `%s'"), name);
252b5132
RH
568 fprintf (stderr, _("%s: supported formats:"), program_name);
569 for (m = format_names; m->name != NULL; m++)
570 fprintf (stderr, " %s", m->name);
571 fprintf (stderr, "\n");
572 xexit (1);
573 }
574
575 return m->format;
576}
577
578/* Work out a format type given a file name. If INPUT is non-zero,
579 it's OK to look at the file itself. */
580
581static enum res_format
2da42df6 582format_from_filename (const char *filename, int input)
252b5132
RH
583{
584 const char *ext;
585 FILE *e;
4a594fce 586 bfd_byte b1, b2, b3, b4, b5;
252b5132
RH
587 int magic;
588
589 /* If we have an extension, see if we recognize it as implying a
590 particular format. */
591 ext = strrchr (filename, '.');
592 if (ext != NULL)
593 {
594 const struct format_map *m;
595
596 ++ext;
597 for (m = format_fileexts; m->name != NULL; m++)
598 if (strcasecmp (m->name, ext) == 0)
599 return m->format;
600 }
601
602 /* If we don't recognize the name of an output file, assume it's a
603 COFF file. */
252b5132
RH
604 if (! input)
605 return RES_FORMAT_COFF;
606
607 /* Read the first few bytes of the file to see if we can guess what
608 it is. */
252b5132
RH
609 e = fopen (filename, FOPEN_RB);
610 if (e == NULL)
611 fatal ("%s: %s", filename, strerror (errno));
612
613 b1 = getc (e);
614 b2 = getc (e);
615 b3 = getc (e);
616 b4 = getc (e);
617 b5 = getc (e);
618
619 fclose (e);
620
621 /* A PE executable starts with 0x4d 0x5a. */
622 if (b1 == 0x4d && b2 == 0x5a)
623 return RES_FORMAT_COFF;
624
625 /* A COFF .o file starts with a COFF magic number. */
626 magic = (b2 << 8) | b1;
627 switch (magic)
628 {
629 case 0x14c: /* i386 */
630 case 0x166: /* MIPS */
631 case 0x184: /* Alpha */
632 case 0x268: /* 68k */
633 case 0x1f0: /* PowerPC */
634 case 0x290: /* PA */
635 return RES_FORMAT_COFF;
636 }
637
638 /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0. */
639 if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
640 return RES_FORMAT_RES;
641
642 /* If every character is printable or space, assume it's an RC file. */
3882b010
L
643 if ((ISPRINT (b1) || ISSPACE (b1))
644 && (ISPRINT (b2) || ISSPACE (b2))
645 && (ISPRINT (b3) || ISSPACE (b3))
646 && (ISPRINT (b4) || ISSPACE (b4))
647 && (ISPRINT (b5) || ISSPACE (b5)))
252b5132
RH
648 return RES_FORMAT_RC;
649
650 /* Otherwise, we give up. */
d412a550 651 fatal (_("can not determine type of file `%s'; use the -J option"),
252b5132
RH
652 filename);
653
654 /* Return something to silence the compiler warning. */
655 return RES_FORMAT_UNKNOWN;
656}
657
658/* Print a usage message and exit. */
659
660static void
2da42df6 661usage (FILE *stream, int status)
252b5132 662{
8b53311e 663 fprintf (stream, _("Usage: %s [option(s)] [input-file] [output-file]\n"),
252b5132 664 program_name);
8b53311e
NC
665 fprintf (stream, _(" The options are:\n\
666 -i --input=<file> Name input file\n\
667 -o --output=<file> Name output file\n\
85eb5110 668 -J --input-format=<format> Specify input format\n\
8b53311e
NC
669 -O --output-format=<format> Specify output format\n\
670 -F --target=<target> Specify COFF target\n\
671 --preprocessor=<program> Program to use to preprocess rc file\n\
85eb5110 672 -I --include-dir=<dir> Include directory when preprocessing rc file\n\
8b53311e 673 -D --define <sym>[=<val>] Define SYM when preprocessing rc file\n\
29b058f1 674 -U --undefine <sym> Undefine SYM when preprocessing rc file\n\
8b53311e 675 -v --verbose Verbose - tells you what it's doing\n\
85eb5110 676 -l --language=<val> Set language when reading rc file\n\
8b53311e
NC
677 --use-temp-file Use a temporary file instead of popen to read\n\
678 the preprocessor output\n\
679 --no-use-temp-file Use popen (default)\n"));
252b5132
RH
680#ifdef YYDEBUG
681 fprintf (stream, _("\
8b53311e 682 --yydebug Turn on parser debugging\n"));
252b5132
RH
683#endif
684 fprintf (stream, _("\
3126d709 685 -r Ignored for compatibility with rc\n\
07012eee 686 @<file> Read options from <file>\n\
8b53311e
NC
687 -h --help Print this help message\n\
688 -V --version Print version information\n"));
252b5132
RH
689 fprintf (stream, _("\
690FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
691extension if not specified. A single file name is an input file.\n\
692No input-file is stdin, default rc. No output-file is stdout, default rc.\n"));
8b53311e 693
252b5132 694 list_supported_targets (program_name, stream);
8b53311e 695
92f01d61 696 if (REPORT_BUGS_TO[0] && status == 0)
8ad3436c 697 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
8b53311e 698
252b5132
RH
699 exit (status);
700}
701
8b53311e
NC
702/* Quote characters that will confuse the shell when we run the preprocessor. */
703
704static const char *
2da42df6 705quot (const char *string)
09cda596
DD
706{
707 static char *buf = 0;
708 static int buflen = 0;
709 int slen = strlen (string);
710 const char *src;
711 char *dest;
712
4a594fce 713 if ((buflen < slen * 2 + 2) || ! buf)
09cda596
DD
714 {
715 buflen = slen * 2 + 2;
716 if (buf)
717 free (buf);
718 buf = (char *) xmalloc (buflen);
719 }
720
721 for (src=string, dest=buf; *src; src++, dest++)
722 {
723 if (*src == '(' || *src == ')' || *src == ' ')
724 *dest++ = '\\';
725 *dest = *src;
726 }
727 *dest = 0;
728 return buf;
729}
730
32df8966
NC
731/* Long options. */
732
733/* 150 isn't special; it's just an arbitrary non-ASCII char value. */
734
735#define OPTION_PREPROCESSOR 150
736#define OPTION_USE_TEMP_FILE (OPTION_PREPROCESSOR + 1)
737#define OPTION_NO_USE_TEMP_FILE (OPTION_USE_TEMP_FILE + 1)
738#define OPTION_YYDEBUG (OPTION_NO_USE_TEMP_FILE + 1)
739
740static const struct option long_options[] =
741{
742 {"input", required_argument, 0, 'i'},
743 {"output", required_argument, 0, 'o'},
744 {"input-format", required_argument, 0, 'J'},
745 {"output-format", required_argument, 0, 'O'},
746 {"target", required_argument, 0, 'F'},
747 {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
748 {"include-dir", required_argument, 0, 'I'},
749 {"define", required_argument, 0, 'D'},
750 {"undefine", required_argument, 0, 'U'},
751 {"verbose", no_argument, 0, 'v'},
752 {"language", required_argument, 0, 'l'},
753 {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
754 {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
755 {"yydebug", no_argument, 0, OPTION_YYDEBUG},
756 {"version", no_argument, 0, 'V'},
757 {"help", no_argument, 0, 'h'},
758 {0, no_argument, 0, 0}
759};
760
f7d63484 761/* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes. */
2da42df6 762int main (int, char **);
f7d63484 763
252b5132
RH
764/* The main function. */
765
766int
2da42df6 767main (int argc, char **argv)
252b5132
RH
768{
769 int c;
770 char *input_filename;
771 char *output_filename;
772 enum res_format input_format;
85eb5110 773 enum res_format input_format_tmp;
252b5132
RH
774 enum res_format output_format;
775 char *target;
776 char *preprocessor;
777 char *preprocargs;
09cda596 778 const char *quotedarg;
252b5132 779 int language;
4a594fce 780 rc_res_directory *resources;
5a298d2d 781 int use_temp_file;
252b5132
RH
782
783#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
784 setlocale (LC_MESSAGES, "");
3882b010
L
785#endif
786#if defined (HAVE_SETLOCALE)
787 setlocale (LC_CTYPE, "");
252b5132
RH
788#endif
789 bindtextdomain (PACKAGE, LOCALEDIR);
790 textdomain (PACKAGE);
791
792 program_name = argv[0];
793 xmalloc_set_program_name (program_name);
794
c843b1bb 795 expandargv (&argc, &argv);
869b9d07 796
252b5132
RH
797 bfd_init ();
798 set_default_bfd_target ();
799
800 res_init ();
801
802 input_filename = NULL;
803 output_filename = NULL;
804 input_format = RES_FORMAT_UNKNOWN;
805 output_format = RES_FORMAT_UNKNOWN;
806 target = NULL;
807 preprocessor = NULL;
808 preprocargs = NULL;
f7d63484 809 language = 0x409; /* LANG_ENGLISH, SUBLANG_ENGLISH_US. */
5a298d2d 810 use_temp_file = 0;
252b5132 811
32df8966 812 while ((c = getopt_long (argc, argv, "f:i:l:o:I:J:O:F:D:U:rhHvV", long_options,
252b5132
RH
813 (int *) 0)) != EOF)
814 {
815 switch (c)
816 {
817 case 'i':
818 input_filename = optarg;
819 break;
820
32df8966 821 case 'f':
50c2245b 822 /* For compatibility with rc we accept "-fo <name>" as being the
32df8966
NC
823 equivalent of "-o <name>". We do not advertise this fact
824 though, as we do not want users to use non-GNU like command
825 line switches. */
826 if (*optarg != 'o')
827 fatal (_("invalid option -f\n"));
828 optarg++;
829 if (* optarg == 0)
830 {
831 if (optind == argc)
2da42df6 832 fatal (_("No filename following the -fo option.\n"));
32df8966
NC
833 optarg = argv [optind++];
834 }
835 /* Fall through. */
836
252b5132
RH
837 case 'o':
838 output_filename = optarg;
839 break;
840
85eb5110
NC
841 case 'J':
842 input_format = format_from_name (optarg, 1);
252b5132
RH
843 break;
844
845 case 'O':
85eb5110 846 output_format = format_from_name (optarg, 1);
252b5132
RH
847 break;
848
849 case 'F':
850 target = optarg;
851 break;
852
853 case OPTION_PREPROCESSOR:
854 preprocessor = optarg;
855 break;
856
09cda596 857 case 'D':
29b058f1 858 case 'U':
252b5132
RH
859 if (preprocargs == NULL)
860 {
09cda596
DD
861 quotedarg = quot (optarg);
862 preprocargs = xmalloc (strlen (quotedarg) + 3);
29b058f1 863 sprintf (preprocargs, "-%c%s", c, quotedarg);
252b5132
RH
864 }
865 else
866 {
867 char *n;
868
09cda596
DD
869 quotedarg = quot (optarg);
870 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
29b058f1 871 sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
252b5132
RH
872 free (preprocargs);
873 preprocargs = n;
874 }
875 break;
876
3126d709 877 case 'r':
29b058f1 878 /* Ignored for compatibility with rc. */
3126d709
CF
879 break;
880
751d21b5
DD
881 case 'v':
882 verbose ++;
883 break;
884
85eb5110
NC
885 case 'I':
886 /* For backward compatibility, should be removed in the future. */
887 input_format_tmp = format_from_name (optarg, 0);
888 if (input_format_tmp != RES_FORMAT_UNKNOWN)
889 {
4a594fce
NC
890 fprintf (stderr,
891 _("Option -I is deprecated for setting the input format, please use -J instead.\n"));
85eb5110
NC
892 input_format = input_format_tmp;
893 break;
894 }
2da42df6 895
252b5132
RH
896 if (preprocargs == NULL)
897 {
09cda596
DD
898 quotedarg = quot (optarg);
899 preprocargs = xmalloc (strlen (quotedarg) + 3);
900 sprintf (preprocargs, "-I%s", quotedarg);
252b5132
RH
901 }
902 else
903 {
904 char *n;
905
09cda596
DD
906 quotedarg = quot (optarg);
907 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
908 sprintf (n, "%s -I%s", preprocargs, quotedarg);
252b5132
RH
909 free (preprocargs);
910 preprocargs = n;
911 }
912
913 {
914 struct include_dir *n, **pp;
915
916 n = (struct include_dir *) xmalloc (sizeof *n);
917 n->next = NULL;
918 n->dir = optarg;
919
920 for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
921 ;
922 *pp = n;
923 }
924
925 break;
926
3077f5d8 927 case 'l':
252b5132
RH
928 language = strtol (optarg, (char **) NULL, 16);
929 break;
930
5a298d2d
NC
931 case OPTION_USE_TEMP_FILE:
932 use_temp_file = 1;
933 break;
934
935 case OPTION_NO_USE_TEMP_FILE:
936 use_temp_file = 0;
937 break;
938
252b5132
RH
939#ifdef YYDEBUG
940 case OPTION_YYDEBUG:
941 yydebug = 1;
942 break;
943#endif
944
8b53311e
NC
945 case 'h':
946 case 'H':
252b5132
RH
947 usage (stdout, 0);
948 break;
949
8b53311e 950 case 'V':
252b5132
RH
951 print_version ("windres");
952 break;
953
954 default:
955 usage (stderr, 1);
956 break;
957 }
958 }
959
960 if (input_filename == NULL && optind < argc)
961 {
962 input_filename = argv[optind];
963 ++optind;
964 }
965
966 if (output_filename == NULL && optind < argc)
967 {
968 output_filename = argv[optind];
969 ++optind;
970 }
971
972 if (argc != optind)
973 usage (stderr, 1);
974
975 if (input_format == RES_FORMAT_UNKNOWN)
976 {
977 if (input_filename == NULL)
978 input_format = RES_FORMAT_RC;
979 else
980 input_format = format_from_filename (input_filename, 1);
981 }
982
983 if (output_format == RES_FORMAT_UNKNOWN)
984 {
985 if (output_filename == NULL)
986 output_format = RES_FORMAT_RC;
987 else
988 output_format = format_from_filename (output_filename, 0);
989 }
990
4a594fce
NC
991 set_endianess (NULL, target);
992
252b5132 993 /* Read the input file. */
252b5132
RH
994 switch (input_format)
995 {
996 default:
997 abort ();
998 case RES_FORMAT_RC:
999 resources = read_rc_file (input_filename, preprocessor, preprocargs,
5a298d2d 1000 language, use_temp_file);
252b5132
RH
1001 break;
1002 case RES_FORMAT_RES:
1003 resources = read_res_file (input_filename);
1004 break;
1005 case RES_FORMAT_COFF:
1006 resources = read_coff_rsrc (input_filename, target);
1007 break;
1008 }
1009
1010 if (resources == NULL)
1011 fatal (_("no resources"));
1012
1013 /* Sort the resources. This is required for COFF, convenient for
1014 rc, and unimportant for res. */
252b5132
RH
1015 resources = sort_resources (resources);
1016
1017 /* Write the output file. */
252b5132
RH
1018 reswr_init ();
1019
1020 switch (output_format)
1021 {
1022 default:
1023 abort ();
1024 case RES_FORMAT_RC:
1025 write_rc_file (output_filename, resources);
1026 break;
1027 case RES_FORMAT_RES:
1028 write_res_file (output_filename, resources);
1029 break;
1030 case RES_FORMAT_COFF:
1031 write_coff_file (output_filename, target, resources);
1032 break;
1033 }
1034
1035 xexit (0);
1036 return 0;
1037}
4a594fce
NC
1038
1039static void set_endianess (bfd *abfd, const char *target)
1040{
1041 const bfd_target *target_vec;
1042
1043 def_target_arch = NULL;
1044 target_vec = bfd_find_target (target, abfd);
1045 if (! target_vec)
1046 fatal ("Can't detect target endianess and architecture.");
1047 target_is_bigendian = ((target_vec->byteorder == BFD_ENDIAN_BIG) ? 1 : 0);
1048 {
1049 const char *tname = target_vec->name;
1050 const char **arch = bfd_arch_list();
1051 if (arch && tname)
1052 {
1053 if (strchr (tname, '-') != NULL)
1054 tname = strchr (tname, '-') + 1;
1055 while (*arch != NULL)
1056 {
1057 const char *in_a = strstr (*arch, tname);
1058 char end_ch = (in_a ? in_a[strlen(tname)] : 0);
1059 if (in_a && (in_a == *arch || in_a[-1] == ':')
1060 && end_ch == 0)
1061 {
1062 def_target_arch = *arch;
1063 break;
1064 }
1065 arch++;
1066 }
1067 }
1068 if (! def_target_arch)
1069 fatal ("Can't detect architecture.");
1070 }
1071}
1072
1073bfd *
1074windres_open_as_binary (const char *filename, int rdmode)
1075{
1076 bfd *abfd;
1077
1078 abfd = (rdmode ? bfd_openr (filename, "binary") : bfd_openw (filename, "binary"));
1079 if (! abfd)
1080 fatal ("can't open `%s' for %s", filename, (rdmode ? "input" : "output"));
1081
1082 if (rdmode && ! bfd_check_format (abfd, bfd_object))
1083 fatal ("can't open `%s' for input.", filename);
1084
1085 return abfd;
1086}
1087
1088void
1089set_windres_bfd_endianess (windres_bfd *wrbfd, int is_bigendian)
1090{
1091 assert (!! wrbfd);
1092 switch (WR_KIND(wrbfd))
1093 {
1094 case WR_KIND_BFD_BIN_L:
1095 if (is_bigendian)
1096 WR_KIND(wrbfd) = WR_KIND_BFD_BIN_B;
1097 break;
1098 case WR_KIND_BFD_BIN_B:
1099 if (! is_bigendian)
1100 WR_KIND(wrbfd) = WR_KIND_BFD_BIN_L;
1101 break;
1102 default:
1103 /* only binary bfd can be overriden. */
1104 abort ();
1105 }
1106}
1107
1108void
1109set_windres_bfd (windres_bfd *wrbfd, bfd *abfd, asection *sec, rc_uint_type kind)
1110{
1111 assert (!! wrbfd);
1112 switch (kind)
1113 {
1114 case WR_KIND_TARGET:
1115 abfd = NULL;
1116 sec = NULL;
1117 break;
1118 case WR_KIND_BFD:
1119 case WR_KIND_BFD_BIN_L:
1120 case WR_KIND_BFD_BIN_B:
1121 assert (!! abfd);
1122 assert (!!sec);
1123 break;
1124 default:
1125 abort ();
1126 }
1127 WR_KIND(wrbfd) = kind;
1128 WR_BFD(wrbfd) = abfd;
1129 WR_SECTION(wrbfd) = sec;
1130}
1131
1132void
1133set_windres_bfd_content(windres_bfd *wrbfd, const void *data, rc_uint_type off,
1134 rc_uint_type length)
1135{
1136 if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1137 {
1138 if (! bfd_set_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1139 bfd_fatal ("bfd_set_section_contents");
1140 }
1141 else
1142 abort ();
1143}
1144
1145void
1146get_windres_bfd_content(windres_bfd *wrbfd, void *data, rc_uint_type off,
1147 rc_uint_type length)
1148{
1149 if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1150 {
1151 if (! bfd_get_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1152 bfd_fatal ("bfd_get_section_contents");
1153 }
1154 else
1155 abort ();
1156}
1157
1158void
1159windres_put_8 (windres_bfd *wrbfd, void *p, rc_uint_type value)
1160{
1161 switch (WR_KIND(wrbfd))
1162 {
1163 case WR_KIND_TARGET:
1164 target_put_8 (p, value);
1165 break;
1166 case WR_KIND_BFD:
1167 case WR_KIND_BFD_BIN_L:
1168 case WR_KIND_BFD_BIN_B:
1169 bfd_put_8 (WR_BFD(wrbfd), value, p);
1170 break;
1171 default:
1172 abort ();
1173 }
1174}
1175
1176void
1177windres_put_16 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1178{
1179 switch (WR_KIND(wrbfd))
1180 {
1181 case WR_KIND_TARGET:
1182 target_put_16 (data, value);
1183 break;
1184 case WR_KIND_BFD:
1185 case WR_KIND_BFD_BIN_B:
1186 bfd_put_16 (WR_BFD(wrbfd), value, data);
1187 break;
1188 case WR_KIND_BFD_BIN_L:
1189 bfd_putl16 (value, data);
1190 break;
1191 default:
1192 abort ();
1193 }
1194}
1195
1196void
1197windres_put_32 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1198{
1199 switch (WR_KIND(wrbfd))
1200 {
1201 case WR_KIND_TARGET:
1202 target_put_32 (data, value);
1203 break;
1204 case WR_KIND_BFD:
1205 case WR_KIND_BFD_BIN_B:
1206 bfd_put_32 (WR_BFD(wrbfd), value, data);
1207 break;
1208 case WR_KIND_BFD_BIN_L:
1209 bfd_putl32 (value, data);
1210 break;
1211 default:
1212 abort ();
1213 }
1214}
1215
1216rc_uint_type
1217windres_get_8 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1218{
1219 if (length < 1)
1220 fatal ("windres_get_8: unexpected eob.");
1221 switch (WR_KIND(wrbfd))
1222 {
1223 case WR_KIND_TARGET:
1224 return target_get_8 (data, length);
1225 case WR_KIND_BFD:
1226 case WR_KIND_BFD_BIN_B:
1227 case WR_KIND_BFD_BIN_L:
1228 return bfd_get_8 (WR_BFD(wrbfd), data);
1229 default:
1230 abort ();
1231 }
1232 return 0;
1233}
1234
1235rc_uint_type
1236windres_get_16 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1237{
1238 if (length < 2)
1239 fatal ("windres_get_16: unexpected eob.");
1240 switch (WR_KIND(wrbfd))
1241 {
1242 case WR_KIND_TARGET:
1243 return target_get_16 (data, length);
1244 case WR_KIND_BFD:
1245 case WR_KIND_BFD_BIN_B:
1246 return bfd_get_16 (WR_BFD(wrbfd), data);
1247 case WR_KIND_BFD_BIN_L:
1248 return bfd_getl16 (data);
1249 default:
1250 abort ();
1251 }
1252 return 0;
1253}
1254
1255rc_uint_type
1256windres_get_32 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1257{
1258 if (length < 4)
1259 fatal ("windres_get_32: unexpected eob.");
1260 switch (WR_KIND(wrbfd))
1261 {
1262 case WR_KIND_TARGET:
1263 return target_get_32 (data, length);
1264 case WR_KIND_BFD:
1265 case WR_KIND_BFD_BIN_B:
1266 return bfd_get_32 (WR_BFD(wrbfd), data);
1267 case WR_KIND_BFD_BIN_L:
1268 return bfd_getl32 (data);
1269 default:
1270 abort ();
1271 }
1272 return 0;
1273}
1274
1275static rc_uint_type
1276target_get_8 (const void *p, rc_uint_type length)
1277{
1278 rc_uint_type ret;
1279
1280 if (length < 1)
1281 fatal ("Resource too small for getting 8-bit value.");
1282
1283 ret = (rc_uint_type) *((const bfd_byte *) p);
1284 return ret & 0xff;
1285}
1286
1287static rc_uint_type
1288target_get_16 (const void *p, rc_uint_type length)
1289{
1290 if (length < 2)
1291 fatal ("Resource too small for getting 16-bit value.");
1292
1293 if (target_is_bigendian)
1294 return bfd_getb16 (p);
1295 else
1296 return bfd_getl16 (p);
1297}
1298
1299static rc_uint_type
1300target_get_32 (const void *p, rc_uint_type length)
1301{
1302 if (length < 4)
1303 fatal ("Resource too small for getting 32-bit value.");
1304
1305 if (target_is_bigendian)
1306 return bfd_getb32 (p);
1307 else
1308 return bfd_getl32 (p);
1309}
1310
1311static void
1312target_put_8 (void *p, rc_uint_type value)
1313{
1314 assert (!! p);
1315 *((bfd_byte *) p)=(bfd_byte) value;
1316}
1317
1318static void
1319target_put_16 (void *p, rc_uint_type value)
1320{
1321 assert (!! p);
1322
1323 if (target_is_bigendian)
1324 bfd_putb16 (value, p);
1325 else
1326 bfd_putl16 (value, p);
1327}
1328
1329static void
1330target_put_32 (void *p, rc_uint_type value)
1331{
1332 assert (!! p);
1333
1334 if (target_is_bigendian)
1335 bfd_putb32 (value, p);
1336 else
1337 bfd_putl32 (value, p);
1338}
1339
1340static int isInComment = 0;
1341
1342int wr_printcomment (FILE *e, const char *fmt, ...)
1343{
1344 va_list arg;
1345 int r = 0;
1346
1347 if (isInComment)
1348 r += fprintf (e, "\n ");
1349 else
1350 fprintf (e, "/* ");
1351 isInComment = 1;
1352 if (fmt == NULL)
1353 return r;
1354 va_start (arg, fmt);
1355 r += vfprintf (e, fmt, arg);
1356 va_end (arg);
1357 return r;
1358}
1359
1360int wr_print (FILE *e, const char *fmt, ...)
1361{
1362 va_list arg;
1363 int r = 0;
1364 if (isInComment)
1365 r += fprintf (e, ". */\n");
1366 isInComment = 0;
1367 if (! fmt)
1368 return r;
1369 va_start (arg, fmt);
1370 r += vfprintf (e, fmt, arg);
1371 va_end (arg);
1372 return r;
1373}
This page took 0.347249 seconds and 4 git commands to generate.