* elf32-i386.c (elf_i386_info_to_howto): Delete.
[deliverable/binutils-gdb.git] / binutils / windres.c
CommitLineData
252b5132 1/* windres.c -- a program to manipulate Windows resources
29b058f1
NC
2 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003
3 Free Software Foundation, Inc.
252b5132
RH
4 Written by Ian Lance Taylor, Cygnus Support.
5
6 This file is part of GNU Binutils.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 02111-1307, USA. */
22
23/* This program can read and write Windows resources in various
24 formats. In particular, it can act like the rc resource compiler
25 program, and it can act like the cvtres res to COFF conversion
26 program.
27
28 It is based on information taken from the following sources:
29
30 * Microsoft documentation.
31
32 * The rcl program, written by Gunther Ebert
33 <gunther.ebert@ixos-leipzig.de>.
34
29b058f1 35 * The res2coff program, written by Pedro A. Aranda <paag@tid.es>. */
252b5132
RH
36
37#include "bfd.h"
38#include "getopt.h"
39#include "bucomm.h"
40#include "libiberty.h"
3882b010 41#include "safe-ctype.h"
252b5132
RH
42#include "obstack.h"
43#include "windres.h"
252b5132 44#include <assert.h>
252b5132
RH
45#include <time.h>
46
29b058f1 47/* Used by resrc.c at least. */
751d21b5
DD
48
49int verbose = 0;
50
252b5132
RH
51/* An enumeration of format types. */
52
53enum res_format
54{
55 /* Unknown format. */
56 RES_FORMAT_UNKNOWN,
57 /* Textual RC file. */
58 RES_FORMAT_RC,
59 /* Binary RES file. */
60 RES_FORMAT_RES,
61 /* COFF file. */
62 RES_FORMAT_COFF
63};
64
65/* A structure used to map between format types and strings. */
66
67struct format_map
68{
69 const char *name;
70 enum res_format format;
71};
72
73/* A mapping between names and format types. */
74
75static const struct format_map format_names[] =
76{
77 { "rc", RES_FORMAT_RC },
78 { "res", RES_FORMAT_RES },
79 { "coff", RES_FORMAT_COFF },
80 { NULL, RES_FORMAT_UNKNOWN }
81};
82
83/* A mapping from file extensions to format types. */
84
85static const struct format_map format_fileexts[] =
86{
87 { "rc", RES_FORMAT_RC },
88 { "res", RES_FORMAT_RES },
89 { "exe", RES_FORMAT_COFF },
90 { "obj", RES_FORMAT_COFF },
91 { "o", RES_FORMAT_COFF },
92 { NULL, RES_FORMAT_UNKNOWN }
93};
94
95/* A list of include directories. */
96
97struct include_dir
98{
99 struct include_dir *next;
100 char *dir;
101};
102
103static struct include_dir *include_dirs;
104
105/* Long options. */
106
107/* 150 isn't special; it's just an arbitrary non-ASCII char value. */
108
85eb5110 109#define OPTION_PREPROCESSOR 150
29b058f1
NC
110#define OPTION_USE_TEMP_FILE (OPTION_PREPROCESSOR + 1)
111#define OPTION_NO_USE_TEMP_FILE (OPTION_USE_TEMP_FILE + 1)
3077f5d8 112#define OPTION_YYDEBUG (OPTION_NO_USE_TEMP_FILE + 1)
252b5132
RH
113
114static const struct option long_options[] =
115{
29b058f1 116 {"define", required_argument, 0, 'D'},
3077f5d8 117 {"help", no_argument, 0, 'h'},
85eb5110
NC
118 {"include-dir", required_argument, 0, 'I'},
119 {"input-format", required_argument, 0, 'J'},
3077f5d8 120 {"language", required_argument, 0, 'l'},
252b5132
RH
121 {"output-format", required_argument, 0, 'O'},
122 {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
123 {"target", required_argument, 0, 'F'},
29b058f1 124 {"undefine", required_argument, 0, 'U'},
5a298d2d
NC
125 {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
126 {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
751d21b5 127 {"verbose", no_argument, 0, 'v'},
3077f5d8 128 {"version", no_argument, 0, 'V'},
252b5132
RH
129 {"yydebug", no_argument, 0, OPTION_YYDEBUG},
130 {0, no_argument, 0, 0}
131};
132
133/* Static functions. */
134
135static void res_init PARAMS ((void));
136static int extended_menuitems PARAMS ((const struct menuitem *));
85eb5110 137static enum res_format format_from_name PARAMS ((const char *, int));
252b5132
RH
138static enum res_format format_from_filename PARAMS ((const char *, int));
139static void usage PARAMS ((FILE *, int));
140static int cmp_res_entry PARAMS ((const PTR, const PTR));
141static struct res_directory *sort_resources PARAMS ((struct res_directory *));
f7d63484
NC
142static void reswr_init PARAMS ((void));
143static const char * quot PARAMS ((const char *));
252b5132
RH
144\f
145/* When we are building a resource tree, we allocate everything onto
146 an obstack, so that we can free it all at once if we want. */
147
148#define obstack_chunk_alloc xmalloc
149#define obstack_chunk_free free
150
151/* The resource building obstack. */
152
153static struct obstack res_obstack;
154
155/* Initialize the resource building obstack. */
156
157static void
158res_init ()
159{
160 obstack_init (&res_obstack);
161}
162
163/* Allocate space on the resource building obstack. */
164
165PTR
166res_alloc (bytes)
167 size_t bytes;
168{
169 return (PTR) obstack_alloc (&res_obstack, bytes);
170}
171
172/* We also use an obstack to save memory used while writing out a set
173 of resources. */
174
175static struct obstack reswr_obstack;
176
177/* Initialize the resource writing obstack. */
178
179static void
180reswr_init ()
181{
182 obstack_init (&reswr_obstack);
183}
184
185/* Allocate space on the resource writing obstack. */
186
187PTR
188reswr_alloc (bytes)
189 size_t bytes;
190{
191 return (PTR) obstack_alloc (&reswr_obstack, bytes);
192}
193\f
194/* Open a file using the include directory search list. */
195
196FILE *
197open_file_search (filename, mode, errmsg, real_filename)
198 const char *filename;
199 const char *mode;
200 const char *errmsg;
201 char **real_filename;
202{
203 FILE *e;
204 struct include_dir *d;
205
206 e = fopen (filename, mode);
207 if (e != NULL)
208 {
209 *real_filename = xstrdup (filename);
210 return e;
211 }
212
213 if (errno == ENOENT)
214 {
215 for (d = include_dirs; d != NULL; d = d->next)
216 {
217 char *n;
218
219 n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
220 sprintf (n, "%s/%s", d->dir, filename);
221 e = fopen (n, mode);
222 if (e != NULL)
223 {
224 *real_filename = n;
225 return e;
226 }
227
228 if (errno != ENOENT)
229 break;
230 }
231 }
232
233 fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
234
235 /* Return a value to avoid a compiler warning. */
236 return NULL;
237}
238\f
239/* Compare two resource ID's. We consider name entries to come before
240 numeric entries, because that is how they appear in the COFF .rsrc
241 section. */
242
243int
244res_id_cmp (a, b)
245 struct res_id a;
246 struct res_id b;
247{
248 if (! a.named)
249 {
250 if (b.named)
251 return 1;
252 if (a.u.id > b.u.id)
253 return 1;
254 else if (a.u.id < b.u.id)
255 return -1;
256 else
257 return 0;
258 }
259 else
260 {
261 unichar *as, *ase, *bs, *bse;
262
263 if (! b.named)
264 return -1;
265
266 as = a.u.n.name;
267 ase = as + a.u.n.length;
268 bs = b.u.n.name;
269 bse = bs + b.u.n.length;
270
271 while (as < ase)
272 {
273 int i;
274
275 if (bs >= bse)
276 return 1;
277 i = (int) *as - (int) *bs;
278 if (i != 0)
279 return i;
280 ++as;
281 ++bs;
282 }
283
284 if (bs < bse)
285 return -1;
286
287 return 0;
288 }
289}
290
291/* Print a resource ID. */
292
293void
294res_id_print (stream, id, quote)
295 FILE *stream;
296 struct res_id id;
297 int quote;
298{
299 if (! id.named)
300 fprintf (stream, "%lu", id.u.id);
301 else
302 {
303 if (quote)
304 putc ('"', stream);
305 unicode_print (stream, id.u.n.name, id.u.n.length);
306 if (quote)
307 putc ('"', stream);
308 }
309}
310
311/* Print a list of resource ID's. */
312
313void
314res_ids_print (stream, cids, ids)
315 FILE *stream;
316 int cids;
317 const struct res_id *ids;
318{
319 int i;
320
321 for (i = 0; i < cids; i++)
322 {
323 res_id_print (stream, ids[i], 1);
324 if (i + 1 < cids)
325 fprintf (stream, ": ");
326 }
327}
328
329/* Convert an ASCII string to a resource ID. */
330
331void
332res_string_to_id (res_id, string)
333 struct res_id *res_id;
334 const char *string;
335{
336 res_id->named = 1;
337 unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
338}
339
340/* Define a resource. The arguments are the resource tree, RESOURCES,
341 and the location at which to put it in the tree, CIDS and IDS.
342 This returns a newly allocated res_resource structure, which the
343 caller is expected to initialize. If DUPOK is non-zero, then if a
344 resource with this ID exists, it is returned. Otherwise, a warning
345 is issued, and a new resource is created replacing the existing
346 one. */
347
348struct res_resource *
349define_resource (resources, cids, ids, dupok)
350 struct res_directory **resources;
351 int cids;
352 const struct res_id *ids;
353 int dupok;
354{
355 struct res_entry *re = NULL;
356 int i;
357
358 assert (cids > 0);
359 for (i = 0; i < cids; i++)
360 {
361 struct res_entry **pp;
362
363 if (*resources == NULL)
364 {
365 static unsigned long timeval;
366
367 /* Use the same timestamp for every resource created in a
368 single run. */
369 if (timeval == 0)
370 timeval = time (NULL);
371
372 *resources = ((struct res_directory *)
373 res_alloc (sizeof **resources));
374 (*resources)->characteristics = 0;
375 (*resources)->time = timeval;
376 (*resources)->major = 0;
377 (*resources)->minor = 0;
378 (*resources)->entries = NULL;
379 }
380
381 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
382 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
383 break;
384
385 if (*pp != NULL)
386 re = *pp;
387 else
388 {
389 re = (struct res_entry *) res_alloc (sizeof *re);
390 re->next = NULL;
391 re->id = ids[i];
392 if ((i + 1) < cids)
393 {
394 re->subdir = 1;
395 re->u.dir = NULL;
396 }
397 else
398 {
399 re->subdir = 0;
400 re->u.res = NULL;
401 }
402
403 *pp = re;
404 }
405
406 if ((i + 1) < cids)
407 {
408 if (! re->subdir)
409 {
410 fprintf (stderr, "%s: ", program_name);
411 res_ids_print (stderr, i, ids);
412 fprintf (stderr, _(": expected to be a directory\n"));
413 xexit (1);
414 }
415
416 resources = &re->u.dir;
417 }
418 }
419
420 if (re->subdir)
421 {
422 fprintf (stderr, "%s: ", program_name);
423 res_ids_print (stderr, cids, ids);
424 fprintf (stderr, _(": expected to be a leaf\n"));
425 xexit (1);
426 }
427
428 if (re->u.res != NULL)
429 {
430 if (dupok)
431 return re->u.res;
432
433 fprintf (stderr, _("%s: warning: "), program_name);
434 res_ids_print (stderr, cids, ids);
435 fprintf (stderr, _(": duplicate value\n"));
436 }
437
438 re->u.res = ((struct res_resource *)
439 res_alloc (sizeof (struct res_resource)));
e80ff7de 440 memset (re->u.res, 0, sizeof (struct res_resource));
252b5132
RH
441
442 re->u.res->type = RES_TYPE_UNINITIALIZED;
252b5132
RH
443 return re->u.res;
444}
445
446/* Define a standard resource. This is a version of define_resource
447 that just takes type, name, and language arguments. */
448
449struct res_resource *
450define_standard_resource (resources, type, name, language, dupok)
451 struct res_directory **resources;
452 int type;
453 struct res_id name;
454 int language;
455 int dupok;
456{
457 struct res_id a[3];
458
459 a[0].named = 0;
460 a[0].u.id = type;
461 a[1] = name;
462 a[2].named = 0;
463 a[2].u.id = language;
464 return define_resource (resources, 3, a, dupok);
465}
466
467/* Comparison routine for resource sorting. */
468
469static int
470cmp_res_entry (p1, p2)
471 const PTR p1;
472 const PTR p2;
473{
474 const struct res_entry **re1, **re2;
475
476 re1 = (const struct res_entry **) p1;
477 re2 = (const struct res_entry **) p2;
478 return res_id_cmp ((*re1)->id, (*re2)->id);
479}
480
481/* Sort the resources. */
482
483static struct res_directory *
484sort_resources (resdir)
485 struct res_directory *resdir;
486{
487 int c, i;
488 struct res_entry *re;
489 struct res_entry **a;
490
491 if (resdir->entries == NULL)
492 return resdir;
493
494 c = 0;
495 for (re = resdir->entries; re != NULL; re = re->next)
496 ++c;
497
498 /* This is a recursive routine, so using xmalloc is probably better
499 than alloca. */
500 a = (struct res_entry **) xmalloc (c * sizeof (struct res_entry *));
501
502 for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
503 a[i] = re;
504
505 qsort (a, c, sizeof (struct res_entry *), cmp_res_entry);
506
507 resdir->entries = a[0];
508 for (i = 0; i < c - 1; i++)
509 a[i]->next = a[i + 1];
510 a[i]->next = NULL;
511
512 free (a);
513
514 /* Now sort the subdirectories. */
515
516 for (re = resdir->entries; re != NULL; re = re->next)
517 if (re->subdir)
518 re->u.dir = sort_resources (re->u.dir);
519
520 return resdir;
521}
522\f
523/* Return whether the dialog resource DIALOG is a DIALOG or a
524 DIALOGEX. */
525
526int
527extended_dialog (dialog)
528 const struct dialog *dialog;
529{
530 const struct dialog_control *c;
531
532 if (dialog->ex != NULL)
533 return 1;
534
535 for (c = dialog->controls; c != NULL; c = c->next)
536 if (c->data != NULL || c->help != 0)
537 return 1;
538
539 return 0;
540}
541
542/* Return whether MENUITEMS are a MENU or a MENUEX. */
543
544int
545extended_menu (menu)
546 const struct menu *menu;
547{
548 return extended_menuitems (menu->items);
549}
550
551static int
552extended_menuitems (menuitems)
553 const struct menuitem *menuitems;
554{
555 const struct menuitem *mi;
556
557 for (mi = menuitems; mi != NULL; mi = mi->next)
558 {
559 if (mi->help != 0 || mi->state != 0)
560 return 1;
561 if (mi->popup != NULL && mi->id != 0)
562 return 1;
563 if ((mi->type
564 & ~ (MENUITEM_CHECKED
565 | MENUITEM_GRAYED
566 | MENUITEM_HELP
567 | MENUITEM_INACTIVE
568 | MENUITEM_MENUBARBREAK
569 | MENUITEM_MENUBREAK))
570 != 0)
571 return 1;
572 if (mi->popup != NULL)
573 {
574 if (extended_menuitems (mi->popup))
575 return 1;
576 }
577 }
578
579 return 0;
580}
581\f
582/* Convert a string to a format type, or exit if it can't be done. */
583
584static enum res_format
85eb5110 585format_from_name (name, exit_on_error)
252b5132 586 const char *name;
85eb5110 587 int exit_on_error;
252b5132
RH
588{
589 const struct format_map *m;
590
591 for (m = format_names; m->name != NULL; m++)
592 if (strcasecmp (m->name, name) == 0)
593 break;
594
85eb5110 595 if (m->name == NULL && exit_on_error)
252b5132 596 {
37cc8ec1 597 non_fatal (_("unknown format type `%s'"), name);
252b5132
RH
598 fprintf (stderr, _("%s: supported formats:"), program_name);
599 for (m = format_names; m->name != NULL; m++)
600 fprintf (stderr, " %s", m->name);
601 fprintf (stderr, "\n");
602 xexit (1);
603 }
604
605 return m->format;
606}
607
608/* Work out a format type given a file name. If INPUT is non-zero,
609 it's OK to look at the file itself. */
610
611static enum res_format
612format_from_filename (filename, input)
613 const char *filename;
614 int input;
615{
616 const char *ext;
617 FILE *e;
618 unsigned char b1, b2, b3, b4, b5;
619 int magic;
620
621 /* If we have an extension, see if we recognize it as implying a
622 particular format. */
623 ext = strrchr (filename, '.');
624 if (ext != NULL)
625 {
626 const struct format_map *m;
627
628 ++ext;
629 for (m = format_fileexts; m->name != NULL; m++)
630 if (strcasecmp (m->name, ext) == 0)
631 return m->format;
632 }
633
634 /* If we don't recognize the name of an output file, assume it's a
635 COFF file. */
252b5132
RH
636 if (! input)
637 return RES_FORMAT_COFF;
638
639 /* Read the first few bytes of the file to see if we can guess what
640 it is. */
252b5132
RH
641 e = fopen (filename, FOPEN_RB);
642 if (e == NULL)
643 fatal ("%s: %s", filename, strerror (errno));
644
645 b1 = getc (e);
646 b2 = getc (e);
647 b3 = getc (e);
648 b4 = getc (e);
649 b5 = getc (e);
650
651 fclose (e);
652
653 /* A PE executable starts with 0x4d 0x5a. */
654 if (b1 == 0x4d && b2 == 0x5a)
655 return RES_FORMAT_COFF;
656
657 /* A COFF .o file starts with a COFF magic number. */
658 magic = (b2 << 8) | b1;
659 switch (magic)
660 {
661 case 0x14c: /* i386 */
662 case 0x166: /* MIPS */
663 case 0x184: /* Alpha */
664 case 0x268: /* 68k */
665 case 0x1f0: /* PowerPC */
666 case 0x290: /* PA */
667 return RES_FORMAT_COFF;
668 }
669
670 /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0. */
671 if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
672 return RES_FORMAT_RES;
673
674 /* If every character is printable or space, assume it's an RC file. */
3882b010
L
675 if ((ISPRINT (b1) || ISSPACE (b1))
676 && (ISPRINT (b2) || ISSPACE (b2))
677 && (ISPRINT (b3) || ISSPACE (b3))
678 && (ISPRINT (b4) || ISSPACE (b4))
679 && (ISPRINT (b5) || ISSPACE (b5)))
252b5132
RH
680 return RES_FORMAT_RC;
681
682 /* Otherwise, we give up. */
683 fatal (_("can not determine type of file `%s'; use the -I option"),
684 filename);
685
686 /* Return something to silence the compiler warning. */
687 return RES_FORMAT_UNKNOWN;
688}
689
690/* Print a usage message and exit. */
691
692static void
693usage (stream, status)
694 FILE *stream;
695 int status;
696{
8b53311e 697 fprintf (stream, _("Usage: %s [option(s)] [input-file] [output-file]\n"),
252b5132 698 program_name);
8b53311e
NC
699 fprintf (stream, _(" The options are:\n\
700 -i --input=<file> Name input file\n\
701 -o --output=<file> Name output file\n\
85eb5110 702 -J --input-format=<format> Specify input format\n\
8b53311e
NC
703 -O --output-format=<format> Specify output format\n\
704 -F --target=<target> Specify COFF target\n\
705 --preprocessor=<program> Program to use to preprocess rc file\n\
85eb5110 706 -I --include-dir=<dir> Include directory when preprocessing rc file\n\
8b53311e 707 -D --define <sym>[=<val>] Define SYM when preprocessing rc file\n\
29b058f1 708 -U --undefine <sym> Undefine SYM when preprocessing rc file\n\
8b53311e 709 -v --verbose Verbose - tells you what it's doing\n\
85eb5110 710 -l --language=<val> Set language when reading rc file\n\
8b53311e
NC
711 --use-temp-file Use a temporary file instead of popen to read\n\
712 the preprocessor output\n\
713 --no-use-temp-file Use popen (default)\n"));
252b5132
RH
714#ifdef YYDEBUG
715 fprintf (stream, _("\
8b53311e 716 --yydebug Turn on parser debugging\n"));
252b5132
RH
717#endif
718 fprintf (stream, _("\
3126d709 719 -r Ignored for compatibility with rc\n\
8b53311e
NC
720 -h --help Print this help message\n\
721 -V --version Print version information\n"));
252b5132
RH
722 fprintf (stream, _("\
723FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
724extension if not specified. A single file name is an input file.\n\
725No input-file is stdin, default rc. No output-file is stdout, default rc.\n"));
8b53311e 726
252b5132 727 list_supported_targets (program_name, stream);
8b53311e 728
252b5132 729 if (status == 0)
8ad3436c 730 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
8b53311e 731
252b5132
RH
732 exit (status);
733}
734
8b53311e
NC
735/* Quote characters that will confuse the shell when we run the preprocessor. */
736
737static const char *
738quot (string)
09cda596
DD
739 const char *string;
740{
741 static char *buf = 0;
742 static int buflen = 0;
743 int slen = strlen (string);
744 const char *src;
745 char *dest;
746
747 if ((buflen < slen * 2 + 2) || !buf)
748 {
749 buflen = slen * 2 + 2;
750 if (buf)
751 free (buf);
752 buf = (char *) xmalloc (buflen);
753 }
754
755 for (src=string, dest=buf; *src; src++, dest++)
756 {
757 if (*src == '(' || *src == ')' || *src == ' ')
758 *dest++ = '\\';
759 *dest = *src;
760 }
761 *dest = 0;
762 return buf;
763}
764
f7d63484
NC
765/* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes. */
766int main PARAMS ((int, char **));
767
252b5132
RH
768/* The main function. */
769
770int
771main (argc, argv)
772 int argc;
773 char **argv;
774{
775 int c;
776 char *input_filename;
777 char *output_filename;
778 enum res_format input_format;
85eb5110 779 enum res_format input_format_tmp;
252b5132
RH
780 enum res_format output_format;
781 char *target;
782 char *preprocessor;
783 char *preprocargs;
09cda596 784 const char *quotedarg;
252b5132
RH
785 int language;
786 struct res_directory *resources;
5a298d2d 787 int use_temp_file;
252b5132
RH
788
789#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
790 setlocale (LC_MESSAGES, "");
3882b010
L
791#endif
792#if defined (HAVE_SETLOCALE)
793 setlocale (LC_CTYPE, "");
252b5132
RH
794#endif
795 bindtextdomain (PACKAGE, LOCALEDIR);
796 textdomain (PACKAGE);
797
798 program_name = argv[0];
799 xmalloc_set_program_name (program_name);
800
801 bfd_init ();
802 set_default_bfd_target ();
803
804 res_init ();
805
806 input_filename = NULL;
807 output_filename = NULL;
808 input_format = RES_FORMAT_UNKNOWN;
809 output_format = RES_FORMAT_UNKNOWN;
810 target = NULL;
811 preprocessor = NULL;
812 preprocargs = NULL;
f7d63484 813 language = 0x409; /* LANG_ENGLISH, SUBLANG_ENGLISH_US. */
5a298d2d 814 use_temp_file = 0;
252b5132 815
85eb5110 816 while ((c = getopt_long (argc, argv, "i:l:o:I:J:O:F:D:U:rhHvV", long_options,
252b5132
RH
817 (int *) 0)) != EOF)
818 {
819 switch (c)
820 {
821 case 'i':
822 input_filename = optarg;
823 break;
824
825 case 'o':
826 output_filename = optarg;
827 break;
828
85eb5110
NC
829 case 'J':
830 input_format = format_from_name (optarg, 1);
252b5132
RH
831 break;
832
833 case 'O':
85eb5110 834 output_format = format_from_name (optarg, 1);
252b5132
RH
835 break;
836
837 case 'F':
838 target = optarg;
839 break;
840
841 case OPTION_PREPROCESSOR:
842 preprocessor = optarg;
843 break;
844
09cda596 845 case 'D':
29b058f1 846 case 'U':
252b5132
RH
847 if (preprocargs == NULL)
848 {
09cda596
DD
849 quotedarg = quot (optarg);
850 preprocargs = xmalloc (strlen (quotedarg) + 3);
29b058f1 851 sprintf (preprocargs, "-%c%s", c, quotedarg);
252b5132
RH
852 }
853 else
854 {
855 char *n;
856
09cda596
DD
857 quotedarg = quot (optarg);
858 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
29b058f1 859 sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
252b5132
RH
860 free (preprocargs);
861 preprocargs = n;
862 }
863 break;
864
3126d709 865 case 'r':
29b058f1 866 /* Ignored for compatibility with rc. */
3126d709
CF
867 break;
868
751d21b5
DD
869 case 'v':
870 verbose ++;
871 break;
872
85eb5110
NC
873 case 'I':
874 /* For backward compatibility, should be removed in the future. */
875 input_format_tmp = format_from_name (optarg, 0);
876 if (input_format_tmp != RES_FORMAT_UNKNOWN)
877 {
878 fprintf (stderr, _("Option -I is deprecated for setting the input format, please use -J instead.\n"));
879 input_format = input_format_tmp;
880 break;
881 }
882
252b5132
RH
883 if (preprocargs == NULL)
884 {
09cda596
DD
885 quotedarg = quot (optarg);
886 preprocargs = xmalloc (strlen (quotedarg) + 3);
887 sprintf (preprocargs, "-I%s", quotedarg);
252b5132
RH
888 }
889 else
890 {
891 char *n;
892
09cda596
DD
893 quotedarg = quot (optarg);
894 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
895 sprintf (n, "%s -I%s", preprocargs, quotedarg);
252b5132
RH
896 free (preprocargs);
897 preprocargs = n;
898 }
899
900 {
901 struct include_dir *n, **pp;
902
903 n = (struct include_dir *) xmalloc (sizeof *n);
904 n->next = NULL;
905 n->dir = optarg;
906
907 for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
908 ;
909 *pp = n;
910 }
911
912 break;
913
3077f5d8 914 case 'l':
252b5132
RH
915 language = strtol (optarg, (char **) NULL, 16);
916 break;
917
5a298d2d
NC
918 case OPTION_USE_TEMP_FILE:
919 use_temp_file = 1;
920 break;
921
922 case OPTION_NO_USE_TEMP_FILE:
923 use_temp_file = 0;
924 break;
925
252b5132
RH
926#ifdef YYDEBUG
927 case OPTION_YYDEBUG:
928 yydebug = 1;
929 break;
930#endif
931
8b53311e
NC
932 case 'h':
933 case 'H':
252b5132
RH
934 usage (stdout, 0);
935 break;
936
8b53311e 937 case 'V':
252b5132
RH
938 print_version ("windres");
939 break;
940
941 default:
942 usage (stderr, 1);
943 break;
944 }
945 }
946
947 if (input_filename == NULL && optind < argc)
948 {
949 input_filename = argv[optind];
950 ++optind;
951 }
952
953 if (output_filename == NULL && optind < argc)
954 {
955 output_filename = argv[optind];
956 ++optind;
957 }
958
959 if (argc != optind)
960 usage (stderr, 1);
961
962 if (input_format == RES_FORMAT_UNKNOWN)
963 {
964 if (input_filename == NULL)
965 input_format = RES_FORMAT_RC;
966 else
967 input_format = format_from_filename (input_filename, 1);
968 }
969
970 if (output_format == RES_FORMAT_UNKNOWN)
971 {
972 if (output_filename == NULL)
973 output_format = RES_FORMAT_RC;
974 else
975 output_format = format_from_filename (output_filename, 0);
976 }
977
978 /* Read the input file. */
252b5132
RH
979 switch (input_format)
980 {
981 default:
982 abort ();
983 case RES_FORMAT_RC:
984 resources = read_rc_file (input_filename, preprocessor, preprocargs,
5a298d2d 985 language, use_temp_file);
252b5132
RH
986 break;
987 case RES_FORMAT_RES:
988 resources = read_res_file (input_filename);
989 break;
990 case RES_FORMAT_COFF:
991 resources = read_coff_rsrc (input_filename, target);
992 break;
993 }
994
995 if (resources == NULL)
996 fatal (_("no resources"));
997
998 /* Sort the resources. This is required for COFF, convenient for
999 rc, and unimportant for res. */
252b5132
RH
1000 resources = sort_resources (resources);
1001
1002 /* Write the output file. */
252b5132
RH
1003 reswr_init ();
1004
1005 switch (output_format)
1006 {
1007 default:
1008 abort ();
1009 case RES_FORMAT_RC:
1010 write_rc_file (output_filename, resources);
1011 break;
1012 case RES_FORMAT_RES:
1013 write_res_file (output_filename, resources);
1014 break;
1015 case RES_FORMAT_COFF:
1016 write_coff_file (output_filename, target, resources);
1017 break;
1018 }
1019
1020 xexit (0);
1021 return 0;
1022}
1023
This page took 0.184547 seconds and 4 git commands to generate.