* Makefile.am (EXPECT): Set to expect.
[binutils.git] / binutils / windres.c
blob4336f006e74a9f85dafd1fd0ed14ce44b0420898
1 /* windres.c -- a program to manipulate Windows resources
2 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
3 Free Software Foundation, Inc.
4 Written by Ian Lance Taylor, Cygnus Support.
6 This file is part of GNU Binutils.
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.
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.
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., 51 Franklin Street - Fifth Floor, Boston, MA
21 02110-1301, USA. */
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.
28 It is based on information taken from the following sources:
30 * Microsoft documentation.
32 * The rcl program, written by Gunther Ebert
33 <gunther.ebert@ixos-leipzig.de>.
35 * The res2coff program, written by Pedro A. Aranda <paag@tid.es>. */
37 #include "config.h"
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #include <assert.h>
42 #include <time.h>
43 #include "bfd.h"
44 #include "getopt.h"
45 #include "bucomm.h"
46 #include "libiberty.h"
47 #include "safe-ctype.h"
48 #include "obstack.h"
49 #include "windres.h"
51 /* Used by resrc.c at least. */
53 int verbose = 0;
55 /* An enumeration of format types. */
57 enum res_format
59 /* Unknown format. */
60 RES_FORMAT_UNKNOWN,
61 /* Textual RC file. */
62 RES_FORMAT_RC,
63 /* Binary RES file. */
64 RES_FORMAT_RES,
65 /* COFF file. */
66 RES_FORMAT_COFF
69 /* A structure used to map between format types and strings. */
71 struct format_map
73 const char *name;
74 enum res_format format;
77 /* A mapping between names and format types. */
79 static const struct format_map format_names[] =
81 { "rc", RES_FORMAT_RC },
82 { "res", RES_FORMAT_RES },
83 { "coff", RES_FORMAT_COFF },
84 { NULL, RES_FORMAT_UNKNOWN }
87 /* A mapping from file extensions to format types. */
89 static const struct format_map format_fileexts[] =
91 { "rc", RES_FORMAT_RC },
92 { "res", RES_FORMAT_RES },
93 { "exe", RES_FORMAT_COFF },
94 { "obj", RES_FORMAT_COFF },
95 { "o", RES_FORMAT_COFF },
96 { NULL, RES_FORMAT_UNKNOWN }
99 /* A list of include directories. */
101 struct include_dir
103 struct include_dir *next;
104 char *dir;
107 static struct include_dir *include_dirs;
109 /* Static functions. */
111 static void res_init (void);
112 static int extended_menuitems (const struct menuitem *);
113 static enum res_format format_from_name (const char *, int);
114 static enum res_format format_from_filename (const char *, int);
115 static void usage (FILE *, int);
116 static int cmp_res_entry (const void *, const void *);
117 static struct res_directory *sort_resources (struct res_directory *);
118 static void reswr_init (void);
119 static const char * quot (const char *);
121 /* When we are building a resource tree, we allocate everything onto
122 an obstack, so that we can free it all at once if we want. */
124 #define obstack_chunk_alloc xmalloc
125 #define obstack_chunk_free free
127 /* The resource building obstack. */
129 static struct obstack res_obstack;
131 /* Initialize the resource building obstack. */
133 static void
134 res_init (void)
136 obstack_init (&res_obstack);
139 /* Allocate space on the resource building obstack. */
141 void *
142 res_alloc (size_t bytes)
144 return (void *) obstack_alloc (&res_obstack, bytes);
147 /* We also use an obstack to save memory used while writing out a set
148 of resources. */
150 static struct obstack reswr_obstack;
152 /* Initialize the resource writing obstack. */
154 static void
155 reswr_init (void)
157 obstack_init (&reswr_obstack);
160 /* Allocate space on the resource writing obstack. */
162 void *
163 reswr_alloc (size_t bytes)
165 return (void *) obstack_alloc (&reswr_obstack, bytes);
168 /* Open a file using the include directory search list. */
170 FILE *
171 open_file_search (const char *filename, const char *mode, const char *errmsg,
172 char **real_filename)
174 FILE *e;
175 struct include_dir *d;
177 e = fopen (filename, mode);
178 if (e != NULL)
180 *real_filename = xstrdup (filename);
181 return e;
184 if (errno == ENOENT)
186 for (d = include_dirs; d != NULL; d = d->next)
188 char *n;
190 n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
191 sprintf (n, "%s/%s", d->dir, filename);
192 e = fopen (n, mode);
193 if (e != NULL)
195 *real_filename = n;
196 return e;
199 if (errno != ENOENT)
200 break;
204 fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
206 /* Return a value to avoid a compiler warning. */
207 return NULL;
210 /* Compare two resource ID's. We consider name entries to come before
211 numeric entries, because that is how they appear in the COFF .rsrc
212 section. */
215 res_id_cmp (struct res_id a, struct res_id b)
217 if (! a.named)
219 if (b.named)
220 return 1;
221 if (a.u.id > b.u.id)
222 return 1;
223 else if (a.u.id < b.u.id)
224 return -1;
225 else
226 return 0;
228 else
230 unichar *as, *ase, *bs, *bse;
232 if (! b.named)
233 return -1;
235 as = a.u.n.name;
236 ase = as + a.u.n.length;
237 bs = b.u.n.name;
238 bse = bs + b.u.n.length;
240 while (as < ase)
242 int i;
244 if (bs >= bse)
245 return 1;
246 i = (int) *as - (int) *bs;
247 if (i != 0)
248 return i;
249 ++as;
250 ++bs;
253 if (bs < bse)
254 return -1;
256 return 0;
260 /* Print a resource ID. */
262 void
263 res_id_print (FILE *stream, struct res_id id, int quote)
265 if (! id.named)
266 fprintf (stream, "%lu", id.u.id);
267 else
269 if (quote)
270 putc ('"', stream);
271 unicode_print (stream, id.u.n.name, id.u.n.length);
272 if (quote)
273 putc ('"', stream);
277 /* Print a list of resource ID's. */
279 void
280 res_ids_print (FILE *stream, int cids, const struct res_id *ids)
282 int i;
284 for (i = 0; i < cids; i++)
286 res_id_print (stream, ids[i], 1);
287 if (i + 1 < cids)
288 fprintf (stream, ": ");
292 /* Convert an ASCII string to a resource ID. */
294 void
295 res_string_to_id (struct res_id *res_id, const char *string)
297 res_id->named = 1;
298 unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
301 /* Define a resource. The arguments are the resource tree, RESOURCES,
302 and the location at which to put it in the tree, CIDS and IDS.
303 This returns a newly allocated res_resource structure, which the
304 caller is expected to initialize. If DUPOK is non-zero, then if a
305 resource with this ID exists, it is returned. Otherwise, a warning
306 is issued, and a new resource is created replacing the existing
307 one. */
309 struct res_resource *
310 define_resource (struct res_directory **resources, int cids,
311 const struct res_id *ids, int dupok)
313 struct res_entry *re = NULL;
314 int i;
316 assert (cids > 0);
317 for (i = 0; i < cids; i++)
319 struct res_entry **pp;
321 if (*resources == NULL)
323 static unsigned long timeval;
325 /* Use the same timestamp for every resource created in a
326 single run. */
327 if (timeval == 0)
328 timeval = time (NULL);
330 *resources = ((struct res_directory *)
331 res_alloc (sizeof **resources));
332 (*resources)->characteristics = 0;
333 (*resources)->time = timeval;
334 (*resources)->major = 0;
335 (*resources)->minor = 0;
336 (*resources)->entries = NULL;
339 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
340 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
341 break;
343 if (*pp != NULL)
344 re = *pp;
345 else
347 re = (struct res_entry *) res_alloc (sizeof *re);
348 re->next = NULL;
349 re->id = ids[i];
350 if ((i + 1) < cids)
352 re->subdir = 1;
353 re->u.dir = NULL;
355 else
357 re->subdir = 0;
358 re->u.res = NULL;
361 *pp = re;
364 if ((i + 1) < cids)
366 if (! re->subdir)
368 fprintf (stderr, "%s: ", program_name);
369 res_ids_print (stderr, i, ids);
370 fprintf (stderr, _(": expected to be a directory\n"));
371 xexit (1);
374 resources = &re->u.dir;
378 if (re->subdir)
380 fprintf (stderr, "%s: ", program_name);
381 res_ids_print (stderr, cids, ids);
382 fprintf (stderr, _(": expected to be a leaf\n"));
383 xexit (1);
386 if (re->u.res != NULL)
388 if (dupok)
389 return re->u.res;
391 fprintf (stderr, _("%s: warning: "), program_name);
392 res_ids_print (stderr, cids, ids);
393 fprintf (stderr, _(": duplicate value\n"));
396 re->u.res = ((struct res_resource *)
397 res_alloc (sizeof (struct res_resource)));
398 memset (re->u.res, 0, sizeof (struct res_resource));
400 re->u.res->type = RES_TYPE_UNINITIALIZED;
401 return re->u.res;
404 /* Define a standard resource. This is a version of define_resource
405 that just takes type, name, and language arguments. */
407 struct res_resource *
408 define_standard_resource (struct res_directory **resources, int type,
409 struct res_id name, int language, int dupok)
411 struct res_id a[3];
413 a[0].named = 0;
414 a[0].u.id = type;
415 a[1] = name;
416 a[2].named = 0;
417 a[2].u.id = language;
418 return define_resource (resources, 3, a, dupok);
421 /* Comparison routine for resource sorting. */
423 static int
424 cmp_res_entry (const void *p1, const void *p2)
426 const struct res_entry **re1, **re2;
428 re1 = (const struct res_entry **) p1;
429 re2 = (const struct res_entry **) p2;
430 return res_id_cmp ((*re1)->id, (*re2)->id);
433 /* Sort the resources. */
435 static struct res_directory *
436 sort_resources (struct res_directory *resdir)
438 int c, i;
439 struct res_entry *re;
440 struct res_entry **a;
442 if (resdir->entries == NULL)
443 return resdir;
445 c = 0;
446 for (re = resdir->entries; re != NULL; re = re->next)
447 ++c;
449 /* This is a recursive routine, so using xmalloc is probably better
450 than alloca. */
451 a = (struct res_entry **) xmalloc (c * sizeof (struct res_entry *));
453 for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
454 a[i] = re;
456 qsort (a, c, sizeof (struct res_entry *), cmp_res_entry);
458 resdir->entries = a[0];
459 for (i = 0; i < c - 1; i++)
460 a[i]->next = a[i + 1];
461 a[i]->next = NULL;
463 free (a);
465 /* Now sort the subdirectories. */
467 for (re = resdir->entries; re != NULL; re = re->next)
468 if (re->subdir)
469 re->u.dir = sort_resources (re->u.dir);
471 return resdir;
474 /* Return whether the dialog resource DIALOG is a DIALOG or a
475 DIALOGEX. */
478 extended_dialog (const struct dialog *dialog)
480 const struct dialog_control *c;
482 if (dialog->ex != NULL)
483 return 1;
485 for (c = dialog->controls; c != NULL; c = c->next)
486 if (c->data != NULL || c->help != 0)
487 return 1;
489 return 0;
492 /* Return whether MENUITEMS are a MENU or a MENUEX. */
495 extended_menu (const struct menu *menu)
497 return extended_menuitems (menu->items);
500 static int
501 extended_menuitems (const struct menuitem *menuitems)
503 const struct menuitem *mi;
505 for (mi = menuitems; mi != NULL; mi = mi->next)
507 if (mi->help != 0 || mi->state != 0)
508 return 1;
509 if (mi->popup != NULL && mi->id != 0)
510 return 1;
511 if ((mi->type
512 & ~ (MENUITEM_CHECKED
513 | MENUITEM_GRAYED
514 | MENUITEM_HELP
515 | MENUITEM_INACTIVE
516 | MENUITEM_MENUBARBREAK
517 | MENUITEM_MENUBREAK))
518 != 0)
519 return 1;
520 if (mi->popup != NULL)
522 if (extended_menuitems (mi->popup))
523 return 1;
527 return 0;
530 /* Convert a string to a format type, or exit if it can't be done. */
532 static enum res_format
533 format_from_name (const char *name, int exit_on_error)
535 const struct format_map *m;
537 for (m = format_names; m->name != NULL; m++)
538 if (strcasecmp (m->name, name) == 0)
539 break;
541 if (m->name == NULL && exit_on_error)
543 non_fatal (_("unknown format type `%s'"), name);
544 fprintf (stderr, _("%s: supported formats:"), program_name);
545 for (m = format_names; m->name != NULL; m++)
546 fprintf (stderr, " %s", m->name);
547 fprintf (stderr, "\n");
548 xexit (1);
551 return m->format;
554 /* Work out a format type given a file name. If INPUT is non-zero,
555 it's OK to look at the file itself. */
557 static enum res_format
558 format_from_filename (const char *filename, int input)
560 const char *ext;
561 FILE *e;
562 unsigned char b1, b2, b3, b4, b5;
563 int magic;
565 /* If we have an extension, see if we recognize it as implying a
566 particular format. */
567 ext = strrchr (filename, '.');
568 if (ext != NULL)
570 const struct format_map *m;
572 ++ext;
573 for (m = format_fileexts; m->name != NULL; m++)
574 if (strcasecmp (m->name, ext) == 0)
575 return m->format;
578 /* If we don't recognize the name of an output file, assume it's a
579 COFF file. */
580 if (! input)
581 return RES_FORMAT_COFF;
583 /* Read the first few bytes of the file to see if we can guess what
584 it is. */
585 e = fopen (filename, FOPEN_RB);
586 if (e == NULL)
587 fatal ("%s: %s", filename, strerror (errno));
589 b1 = getc (e);
590 b2 = getc (e);
591 b3 = getc (e);
592 b4 = getc (e);
593 b5 = getc (e);
595 fclose (e);
597 /* A PE executable starts with 0x4d 0x5a. */
598 if (b1 == 0x4d && b2 == 0x5a)
599 return RES_FORMAT_COFF;
601 /* A COFF .o file starts with a COFF magic number. */
602 magic = (b2 << 8) | b1;
603 switch (magic)
605 case 0x14c: /* i386 */
606 case 0x166: /* MIPS */
607 case 0x184: /* Alpha */
608 case 0x268: /* 68k */
609 case 0x1f0: /* PowerPC */
610 case 0x290: /* PA */
611 return RES_FORMAT_COFF;
614 /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0. */
615 if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
616 return RES_FORMAT_RES;
618 /* If every character is printable or space, assume it's an RC file. */
619 if ((ISPRINT (b1) || ISSPACE (b1))
620 && (ISPRINT (b2) || ISSPACE (b2))
621 && (ISPRINT (b3) || ISSPACE (b3))
622 && (ISPRINT (b4) || ISSPACE (b4))
623 && (ISPRINT (b5) || ISSPACE (b5)))
624 return RES_FORMAT_RC;
626 /* Otherwise, we give up. */
627 fatal (_("can not determine type of file `%s'; use the -J option"),
628 filename);
630 /* Return something to silence the compiler warning. */
631 return RES_FORMAT_UNKNOWN;
634 /* Print a usage message and exit. */
636 static void
637 usage (FILE *stream, int status)
639 fprintf (stream, _("Usage: %s [option(s)] [input-file] [output-file]\n"),
640 program_name);
641 fprintf (stream, _(" The options are:\n\
642 -i --input=<file> Name input file\n\
643 -o --output=<file> Name output file\n\
644 -J --input-format=<format> Specify input format\n\
645 -O --output-format=<format> Specify output format\n\
646 -F --target=<target> Specify COFF target\n\
647 --preprocessor=<program> Program to use to preprocess rc file\n\
648 -I --include-dir=<dir> Include directory when preprocessing rc file\n\
649 -D --define <sym>[=<val>] Define SYM when preprocessing rc file\n\
650 -U --undefine <sym> Undefine SYM when preprocessing rc file\n\
651 -v --verbose Verbose - tells you what it's doing\n\
652 -l --language=<val> Set language when reading rc file\n\
653 --use-temp-file Use a temporary file instead of popen to read\n\
654 the preprocessor output\n\
655 --no-use-temp-file Use popen (default)\n"));
656 #ifdef YYDEBUG
657 fprintf (stream, _("\
658 --yydebug Turn on parser debugging\n"));
659 #endif
660 fprintf (stream, _("\
661 -r Ignored for compatibility with rc\n\
662 -h --help Print this help message\n\
663 -V --version Print version information\n"));
664 fprintf (stream, _("\
665 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
666 extension if not specified. A single file name is an input file.\n\
667 No input-file is stdin, default rc. No output-file is stdout, default rc.\n"));
669 list_supported_targets (program_name, stream);
671 if (status == 0)
672 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
674 exit (status);
677 /* Quote characters that will confuse the shell when we run the preprocessor. */
679 static const char *
680 quot (const char *string)
682 static char *buf = 0;
683 static int buflen = 0;
684 int slen = strlen (string);
685 const char *src;
686 char *dest;
688 if ((buflen < slen * 2 + 2) || !buf)
690 buflen = slen * 2 + 2;
691 if (buf)
692 free (buf);
693 buf = (char *) xmalloc (buflen);
696 for (src=string, dest=buf; *src; src++, dest++)
698 if (*src == '(' || *src == ')' || *src == ' ')
699 *dest++ = '\\';
700 *dest = *src;
702 *dest = 0;
703 return buf;
706 /* Long options. */
708 /* 150 isn't special; it's just an arbitrary non-ASCII char value. */
710 #define OPTION_PREPROCESSOR 150
711 #define OPTION_USE_TEMP_FILE (OPTION_PREPROCESSOR + 1)
712 #define OPTION_NO_USE_TEMP_FILE (OPTION_USE_TEMP_FILE + 1)
713 #define OPTION_YYDEBUG (OPTION_NO_USE_TEMP_FILE + 1)
715 static const struct option long_options[] =
717 {"input", required_argument, 0, 'i'},
718 {"output", required_argument, 0, 'o'},
719 {"input-format", required_argument, 0, 'J'},
720 {"output-format", required_argument, 0, 'O'},
721 {"target", required_argument, 0, 'F'},
722 {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
723 {"include-dir", required_argument, 0, 'I'},
724 {"define", required_argument, 0, 'D'},
725 {"undefine", required_argument, 0, 'U'},
726 {"verbose", no_argument, 0, 'v'},
727 {"language", required_argument, 0, 'l'},
728 {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
729 {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
730 {"yydebug", no_argument, 0, OPTION_YYDEBUG},
731 {"version", no_argument, 0, 'V'},
732 {"help", no_argument, 0, 'h'},
733 {0, no_argument, 0, 0}
736 /* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes. */
737 int main (int, char **);
739 /* The main function. */
742 main (int argc, char **argv)
744 int c;
745 char *input_filename;
746 char *output_filename;
747 enum res_format input_format;
748 enum res_format input_format_tmp;
749 enum res_format output_format;
750 char *target;
751 char *preprocessor;
752 char *preprocargs;
753 const char *quotedarg;
754 int language;
755 struct res_directory *resources;
756 int use_temp_file;
758 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
759 setlocale (LC_MESSAGES, "");
760 #endif
761 #if defined (HAVE_SETLOCALE)
762 setlocale (LC_CTYPE, "");
763 #endif
764 bindtextdomain (PACKAGE, LOCALEDIR);
765 textdomain (PACKAGE);
767 program_name = argv[0];
768 xmalloc_set_program_name (program_name);
770 bfd_init ();
771 set_default_bfd_target ();
773 res_init ();
775 input_filename = NULL;
776 output_filename = NULL;
777 input_format = RES_FORMAT_UNKNOWN;
778 output_format = RES_FORMAT_UNKNOWN;
779 target = NULL;
780 preprocessor = NULL;
781 preprocargs = NULL;
782 language = 0x409; /* LANG_ENGLISH, SUBLANG_ENGLISH_US. */
783 use_temp_file = 0;
785 while ((c = getopt_long (argc, argv, "f:i:l:o:I:J:O:F:D:U:rhHvV", long_options,
786 (int *) 0)) != EOF)
788 switch (c)
790 case 'i':
791 input_filename = optarg;
792 break;
794 case 'f':
795 /* For compatibility with rc we accept "-fo <name>" as being the
796 equivalent of "-o <name>". We do not advertise this fact
797 though, as we do not want users to use non-GNU like command
798 line switches. */
799 if (*optarg != 'o')
800 fatal (_("invalid option -f\n"));
801 optarg++;
802 if (* optarg == 0)
804 if (optind == argc)
805 fatal (_("No filename following the -fo option.\n"));
806 optarg = argv [optind++];
808 /* Fall through. */
810 case 'o':
811 output_filename = optarg;
812 break;
814 case 'J':
815 input_format = format_from_name (optarg, 1);
816 break;
818 case 'O':
819 output_format = format_from_name (optarg, 1);
820 break;
822 case 'F':
823 target = optarg;
824 break;
826 case OPTION_PREPROCESSOR:
827 preprocessor = optarg;
828 break;
830 case 'D':
831 case 'U':
832 if (preprocargs == NULL)
834 quotedarg = quot (optarg);
835 preprocargs = xmalloc (strlen (quotedarg) + 3);
836 sprintf (preprocargs, "-%c%s", c, quotedarg);
838 else
840 char *n;
842 quotedarg = quot (optarg);
843 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
844 sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
845 free (preprocargs);
846 preprocargs = n;
848 break;
850 case 'r':
851 /* Ignored for compatibility with rc. */
852 break;
854 case 'v':
855 verbose ++;
856 break;
858 case 'I':
859 /* For backward compatibility, should be removed in the future. */
860 input_format_tmp = format_from_name (optarg, 0);
861 if (input_format_tmp != RES_FORMAT_UNKNOWN)
863 fprintf (stderr, _("Option -I is deprecated for setting the input format, please use -J instead.\n"));
864 input_format = input_format_tmp;
865 break;
868 if (preprocargs == NULL)
870 quotedarg = quot (optarg);
871 preprocargs = xmalloc (strlen (quotedarg) + 3);
872 sprintf (preprocargs, "-I%s", quotedarg);
874 else
876 char *n;
878 quotedarg = quot (optarg);
879 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
880 sprintf (n, "%s -I%s", preprocargs, quotedarg);
881 free (preprocargs);
882 preprocargs = n;
886 struct include_dir *n, **pp;
888 n = (struct include_dir *) xmalloc (sizeof *n);
889 n->next = NULL;
890 n->dir = optarg;
892 for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
894 *pp = n;
897 break;
899 case 'l':
900 language = strtol (optarg, (char **) NULL, 16);
901 break;
903 case OPTION_USE_TEMP_FILE:
904 use_temp_file = 1;
905 break;
907 case OPTION_NO_USE_TEMP_FILE:
908 use_temp_file = 0;
909 break;
911 #ifdef YYDEBUG
912 case OPTION_YYDEBUG:
913 yydebug = 1;
914 break;
915 #endif
917 case 'h':
918 case 'H':
919 usage (stdout, 0);
920 break;
922 case 'V':
923 print_version ("windres");
924 break;
926 default:
927 usage (stderr, 1);
928 break;
932 if (input_filename == NULL && optind < argc)
934 input_filename = argv[optind];
935 ++optind;
938 if (output_filename == NULL && optind < argc)
940 output_filename = argv[optind];
941 ++optind;
944 if (argc != optind)
945 usage (stderr, 1);
947 if (input_format == RES_FORMAT_UNKNOWN)
949 if (input_filename == NULL)
950 input_format = RES_FORMAT_RC;
951 else
952 input_format = format_from_filename (input_filename, 1);
955 if (output_format == RES_FORMAT_UNKNOWN)
957 if (output_filename == NULL)
958 output_format = RES_FORMAT_RC;
959 else
960 output_format = format_from_filename (output_filename, 0);
963 /* Read the input file. */
964 switch (input_format)
966 default:
967 abort ();
968 case RES_FORMAT_RC:
969 resources = read_rc_file (input_filename, preprocessor, preprocargs,
970 language, use_temp_file);
971 break;
972 case RES_FORMAT_RES:
973 resources = read_res_file (input_filename);
974 break;
975 case RES_FORMAT_COFF:
976 resources = read_coff_rsrc (input_filename, target);
977 break;
980 if (resources == NULL)
981 fatal (_("no resources"));
983 /* Sort the resources. This is required for COFF, convenient for
984 rc, and unimportant for res. */
985 resources = sort_resources (resources);
987 /* Write the output file. */
988 reswr_init ();
990 switch (output_format)
992 default:
993 abort ();
994 case RES_FORMAT_RC:
995 write_rc_file (output_filename, resources);
996 break;
997 case RES_FORMAT_RES:
998 write_res_file (output_filename, resources);
999 break;
1000 case RES_FORMAT_COFF:
1001 write_coff_file (output_filename, target, resources);
1002 break;
1005 xexit (0);
1006 return 0;