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