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