* windres.c (usage): Report -r option.
[external/binutils.git] / binutils / windres.c
1 /* windres.c -- a program to manipulate Windows resources
2    Copyright 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
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      <gunther.ebert@ixos-leipzig.de>.
33
34    * The res2coff program, written by Pedro A. Aranda <paag@tid.es>.
35
36    */
37
38 #include "bfd.h"
39 #include "getopt.h"
40 #include "bucomm.h"
41 #include "libiberty.h"
42 #include "safe-ctype.h"
43 #include "obstack.h"
44 #include "windres.h"
45
46 #include <assert.h>
47 #include <time.h>
48
49 /* used by resrc.c at least */
50
51 int verbose = 0;
52
53 /* An enumeration of format types.  */
54
55 enum 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
69 struct format_map
70 {
71   const char *name;
72   enum res_format format;
73 };
74
75 /* A mapping between names and format types.  */
76
77 static 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
87 static 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
99 struct include_dir
100 {
101   struct include_dir *next;
102   char *dir;
103 };
104
105 static 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)
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)
119 #define OPTION_YYDEBUG (OPTION_VERSION + 1)
120
121 static 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'},
131   {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
132   {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
133   {"verbose", no_argument, 0, 'v'},
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
141 static void res_init PARAMS ((void));
142 static int extended_menuitems PARAMS ((const struct menuitem *));
143 static enum res_format format_from_name PARAMS ((const char *));
144 static enum res_format format_from_filename PARAMS ((const char *, int));
145 static void usage PARAMS ((FILE *, int));
146 static int cmp_res_entry PARAMS ((const PTR, const PTR));
147 static struct res_directory *sort_resources PARAMS ((struct res_directory *));
148 static void reswr_init PARAMS ((void));
149 static const char * quot PARAMS ((const char *));
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
159 static struct obstack res_obstack;
160
161 /* Initialize the resource building obstack.  */
162
163 static void
164 res_init ()
165 {
166   obstack_init (&res_obstack);
167 }
168
169 /* Allocate space on the resource building obstack.  */
170
171 PTR
172 res_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
181 static struct obstack reswr_obstack;
182
183 /* Initialize the resource writing obstack.  */
184
185 static void
186 reswr_init ()
187 {
188   obstack_init (&reswr_obstack);
189 }
190
191 /* Allocate space on the resource writing obstack.  */
192
193 PTR
194 reswr_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
202 FILE *
203 open_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
249 int
250 res_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
299 void
300 res_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
319 void
320 res_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
337 void
338 res_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
354 struct res_resource *
355 define_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)));
446   memset (re->u.res, 0, sizeof (struct res_resource));
447
448   re->u.res->type = RES_TYPE_UNINITIALIZED;
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
455 struct res_resource *
456 define_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
475 static int
476 cmp_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
489 static struct res_directory *
490 sort_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
532 int
533 extended_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
550 int
551 extended_menu (menu)
552      const struct menu *menu;
553 {
554   return extended_menuitems (menu->items);
555 }
556
557 static int
558 extended_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
590 static enum res_format
591 format_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     {
602       non_fatal (_("unknown format type `%s'"), name);
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
616 static enum res_format
617 format_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.  */
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.  */
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.  */
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)))
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
697 static void
698 usage (stream, status)
699      FILE *stream;
700      int status;
701 {
702   fprintf (stream, _("Usage: %s [option(s)] [input-file] [output-file]\n"),
703            program_name);
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"));
718 #ifdef YYDEBUG
719   fprintf (stream, _("\
720      --yydebug                 Turn on parser debugging\n"));
721 #endif
722   fprintf (stream, _("\
723   -r                           Ignored for compatibility with rc\n\
724   -h --help                    Print this help message\n\
725   -V --version                 Print version information\n"));
726   fprintf (stream, _("\
727 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
728 extension if not specified.  A single file name is an input file.\n\
729 No input-file is stdin, default rc.  No output-file is stdout, default rc.\n"));
730
731   list_supported_targets (program_name, stream);
732
733   if (status == 0)
734     fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
735
736   exit (status);
737 }
738
739 /* Quote characters that will confuse the shell when we run the preprocessor.  */
740
741 static const char *
742 quot (string)
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
769 /* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes.  */
770 int main PARAMS ((int, char **));
771
772 /* The main function.  */
773
774 int
775 main (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;
787   const char *quotedarg;
788   int language;
789   struct res_directory *resources;
790   int use_temp_file;
791
792 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
793   setlocale (LC_MESSAGES, "");
794 #endif
795 #if defined (HAVE_SETLOCALE)
796   setlocale (LC_CTYPE, "");
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;
816   language = 0x409;   /* LANG_ENGLISH, SUBLANG_ENGLISH_US.  */
817   use_temp_file = 0;
818
819   while ((c = getopt_long (argc, argv, "i:o:I:O:F:D:rhHvV", long_options,
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
848         case 'D':
849         case OPTION_DEFINE:
850           if (preprocargs == NULL)
851             {
852               quotedarg = quot (optarg);
853               preprocargs = xmalloc (strlen (quotedarg) + 3);
854               sprintf (preprocargs, "-D%s", quotedarg);
855             }
856           else
857             {
858               char *n;
859
860               quotedarg = quot (optarg);
861               n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
862               sprintf (n, "%s -D%s", preprocargs, quotedarg);
863               free (preprocargs);
864               preprocargs = n;
865             }
866           break;
867
868         case 'r':
869           /* Ignored for compatibility with rc */
870           break;
871
872         case 'v':
873           verbose ++;
874           break;
875
876         case OPTION_INCLUDE_DIR:
877           if (preprocargs == NULL)
878             {
879               quotedarg = quot (optarg);
880               preprocargs = xmalloc (strlen (quotedarg) + 3);
881               sprintf (preprocargs, "-I%s", quotedarg);
882             }
883           else
884             {
885               char *n;
886
887               quotedarg = quot (optarg);
888               n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
889               sprintf (n, "%s -I%s", preprocargs, quotedarg);
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
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
920 #ifdef YYDEBUG
921         case OPTION_YYDEBUG:
922           yydebug = 1;
923           break;
924 #endif
925
926         case 'h':
927         case 'H':
928         case OPTION_HELP:
929           usage (stdout, 0);
930           break;
931
932         case 'V':
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,
982                                 language, use_temp_file);
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