Add -l for compatibility with wrc, and rc. Use the short option as a key for
[platform/upstream/binutils.git] / binutils / windres.c
1 /* windres.c -- a program to manipulate Windows resources
2    Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003
3    Free Software Foundation, Inc.
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
35    * The res2coff program, written by Pedro A. Aranda <paag@tid.es>.  */
36
37 #include "bfd.h"
38 #include "getopt.h"
39 #include "bucomm.h"
40 #include "libiberty.h"
41 #include "safe-ctype.h"
42 #include "obstack.h"
43 #include "windres.h"
44 #include <assert.h>
45 #include <time.h>
46
47 /* Used by resrc.c at least.  */
48
49 int verbose = 0;
50
51 /* An enumeration of format types.  */
52
53 enum 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
67 struct format_map
68 {
69   const char *name;
70   enum res_format format;
71 };
72
73 /* A mapping between names and format types.  */
74
75 static 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
85 static 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
97 struct include_dir
98 {
99   struct include_dir *next;
100   char *dir;
101 };
102
103 static 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
109 #define OPTION_INCLUDE_DIR      150
110 #define OPTION_PREPROCESSOR     (OPTION_INCLUDE_DIR + 1)
111 #define OPTION_USE_TEMP_FILE    (OPTION_PREPROCESSOR + 1)
112 #define OPTION_NO_USE_TEMP_FILE (OPTION_USE_TEMP_FILE + 1)
113 #define OPTION_YYDEBUG          (OPTION_NO_USE_TEMP_FILE + 1)
114
115 static const struct option long_options[] =
116 {
117   {"define", required_argument, 0, 'D'},
118   {"help", no_argument, 0, 'h'},
119   {"include-dir", required_argument, 0, OPTION_INCLUDE_DIR},
120   {"input-format", required_argument, 0, 'I'},
121   {"language", required_argument, 0, 'l'},
122   {"output-format", required_argument, 0, 'O'},
123   {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
124   {"target", required_argument, 0, 'F'},
125   {"undefine", required_argument, 0, 'U'},
126   {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
127   {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
128   {"verbose", no_argument, 0, 'v'},
129   {"version", no_argument, 0, 'V'},
130   {"yydebug", no_argument, 0, OPTION_YYDEBUG},
131   {0, no_argument, 0, 0}
132 };
133
134 /* Static functions.  */
135
136 static void res_init PARAMS ((void));
137 static int extended_menuitems PARAMS ((const struct menuitem *));
138 static enum res_format format_from_name PARAMS ((const char *));
139 static enum res_format format_from_filename PARAMS ((const char *, int));
140 static void usage PARAMS ((FILE *, int));
141 static int cmp_res_entry PARAMS ((const PTR, const PTR));
142 static struct res_directory *sort_resources PARAMS ((struct res_directory *));
143 static void reswr_init PARAMS ((void));
144 static const char * quot PARAMS ((const char *));
145 \f
146 /* When we are building a resource tree, we allocate everything onto
147    an obstack, so that we can free it all at once if we want.  */
148
149 #define obstack_chunk_alloc xmalloc
150 #define obstack_chunk_free free
151
152 /* The resource building obstack.  */
153
154 static struct obstack res_obstack;
155
156 /* Initialize the resource building obstack.  */
157
158 static void
159 res_init ()
160 {
161   obstack_init (&res_obstack);
162 }
163
164 /* Allocate space on the resource building obstack.  */
165
166 PTR
167 res_alloc (bytes)
168      size_t bytes;
169 {
170   return (PTR) obstack_alloc (&res_obstack, bytes);
171 }
172
173 /* We also use an obstack to save memory used while writing out a set
174    of resources.  */
175
176 static struct obstack reswr_obstack;
177
178 /* Initialize the resource writing obstack.  */
179
180 static void
181 reswr_init ()
182 {
183   obstack_init (&reswr_obstack);
184 }
185
186 /* Allocate space on the resource writing obstack.  */
187
188 PTR
189 reswr_alloc (bytes)
190      size_t bytes;
191 {
192   return (PTR) obstack_alloc (&reswr_obstack, bytes);
193 }
194 \f
195 /* Open a file using the include directory search list.  */
196
197 FILE *
198 open_file_search (filename, mode, errmsg, real_filename)
199      const char *filename;
200      const char *mode;
201      const char *errmsg;
202      char **real_filename;
203 {
204   FILE *e;
205   struct include_dir *d;
206
207   e = fopen (filename, mode);
208   if (e != NULL)
209     {
210       *real_filename = xstrdup (filename);
211       return e;
212     }
213
214   if (errno == ENOENT)
215     {
216       for (d = include_dirs; d != NULL; d = d->next)
217         {
218           char *n;
219
220           n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
221           sprintf (n, "%s/%s", d->dir, filename);
222           e = fopen (n, mode);
223           if (e != NULL)
224             {
225               *real_filename = n;
226               return e;
227             }
228
229           if (errno != ENOENT)
230             break;
231         }
232     }
233
234   fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
235
236   /* Return a value to avoid a compiler warning.  */
237   return NULL;
238 }
239 \f
240 /* Compare two resource ID's.  We consider name entries to come before
241    numeric entries, because that is how they appear in the COFF .rsrc
242    section.  */
243
244 int
245 res_id_cmp (a, b)
246      struct res_id a;
247      struct res_id b;
248 {
249   if (! a.named)
250     {
251       if (b.named)
252         return 1;
253       if (a.u.id > b.u.id)
254         return 1;
255       else if (a.u.id < b.u.id)
256         return -1;
257       else
258         return 0;
259     }
260   else
261     {
262       unichar *as, *ase, *bs, *bse;
263
264       if (! b.named)
265         return -1;
266
267       as = a.u.n.name;
268       ase = as + a.u.n.length;
269       bs = b.u.n.name;
270       bse = bs + b.u.n.length;
271
272       while (as < ase)
273         {
274           int i;
275
276           if (bs >= bse)
277             return 1;
278           i = (int) *as - (int) *bs;
279           if (i != 0)
280             return i;
281           ++as;
282           ++bs;
283         }
284
285       if (bs < bse)
286         return -1;
287
288       return 0;
289     }
290 }
291
292 /* Print a resource ID.  */
293
294 void
295 res_id_print (stream, id, quote)
296      FILE *stream;
297      struct res_id id;
298      int quote;
299 {
300   if (! id.named)
301     fprintf (stream, "%lu", id.u.id);
302   else
303     {
304       if (quote)
305         putc ('"', stream);
306       unicode_print (stream, id.u.n.name, id.u.n.length);
307       if (quote)
308         putc ('"', stream);
309     }
310 }
311
312 /* Print a list of resource ID's.  */
313
314 void
315 res_ids_print (stream, cids, ids)
316      FILE *stream;
317      int cids;
318      const struct res_id *ids;
319 {
320   int i;
321
322   for (i = 0; i < cids; i++)
323     {
324       res_id_print (stream, ids[i], 1);
325       if (i + 1 < cids)
326         fprintf (stream, ": ");
327     }
328 }
329
330 /* Convert an ASCII string to a resource ID.  */
331
332 void
333 res_string_to_id (res_id, string)
334      struct res_id *res_id;
335      const char *string;
336 {
337   res_id->named = 1;
338   unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
339 }
340
341 /* Define a resource.  The arguments are the resource tree, RESOURCES,
342    and the location at which to put it in the tree, CIDS and IDS.
343    This returns a newly allocated res_resource structure, which the
344    caller is expected to initialize.  If DUPOK is non-zero, then if a
345    resource with this ID exists, it is returned.  Otherwise, a warning
346    is issued, and a new resource is created replacing the existing
347    one.  */
348
349 struct res_resource *
350 define_resource (resources, cids, ids, dupok)
351      struct res_directory **resources;
352      int cids;
353      const struct res_id *ids;
354      int dupok;
355 {
356   struct res_entry *re = NULL;
357   int i;
358
359   assert (cids > 0);
360   for (i = 0; i < cids; i++)
361     {
362       struct res_entry **pp;
363
364       if (*resources == NULL)
365         {
366           static unsigned long timeval;
367
368           /* Use the same timestamp for every resource created in a
369              single run.  */
370           if (timeval == 0)
371             timeval = time (NULL);
372
373           *resources = ((struct res_directory *)
374                         res_alloc (sizeof **resources));
375           (*resources)->characteristics = 0;
376           (*resources)->time = timeval;
377           (*resources)->major = 0;
378           (*resources)->minor = 0;
379           (*resources)->entries = NULL;
380         }
381
382       for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
383         if (res_id_cmp ((*pp)->id, ids[i]) == 0)
384           break;
385
386       if (*pp != NULL)
387         re = *pp;
388       else
389         {
390           re = (struct res_entry *) res_alloc (sizeof *re);
391           re->next = NULL;
392           re->id = ids[i];
393           if ((i + 1) < cids)
394             {
395               re->subdir = 1;
396               re->u.dir = NULL;
397             }
398           else
399             {
400               re->subdir = 0;
401               re->u.res = NULL;
402             }
403
404           *pp = re;
405         }
406
407       if ((i + 1) < cids)
408         {
409           if (! re->subdir)
410             {
411               fprintf (stderr, "%s: ", program_name);
412               res_ids_print (stderr, i, ids);
413               fprintf (stderr, _(": expected to be a directory\n"));
414               xexit (1);
415             }
416
417           resources = &re->u.dir;
418         }
419     }
420
421   if (re->subdir)
422     {
423       fprintf (stderr, "%s: ", program_name);
424       res_ids_print (stderr, cids, ids);
425       fprintf (stderr, _(": expected to be a leaf\n"));
426       xexit (1);
427     }
428
429   if (re->u.res != NULL)
430     {
431       if (dupok)
432         return re->u.res;
433
434       fprintf (stderr, _("%s: warning: "), program_name);
435       res_ids_print (stderr, cids, ids);
436       fprintf (stderr, _(": duplicate value\n"));
437     }
438
439   re->u.res = ((struct res_resource *)
440                res_alloc (sizeof (struct res_resource)));
441   memset (re->u.res, 0, sizeof (struct res_resource));
442
443   re->u.res->type = RES_TYPE_UNINITIALIZED;
444   return re->u.res;
445 }
446
447 /* Define a standard resource.  This is a version of define_resource
448    that just takes type, name, and language arguments.  */
449
450 struct res_resource *
451 define_standard_resource (resources, type, name, language, dupok)
452      struct res_directory **resources;
453      int type;
454      struct res_id name;
455      int language;
456      int dupok;
457 {
458   struct res_id a[3];
459
460   a[0].named = 0;
461   a[0].u.id = type;
462   a[1] = name;
463   a[2].named = 0;
464   a[2].u.id = language;
465   return define_resource (resources, 3, a, dupok);
466 }
467
468 /* Comparison routine for resource sorting.  */
469
470 static int
471 cmp_res_entry (p1, p2)
472      const PTR p1;
473      const PTR p2;
474 {
475   const struct res_entry **re1, **re2;
476
477   re1 = (const struct res_entry **) p1;
478   re2 = (const struct res_entry **) p2;
479   return res_id_cmp ((*re1)->id, (*re2)->id);
480 }
481
482 /* Sort the resources.  */
483
484 static struct res_directory *
485 sort_resources (resdir)
486      struct res_directory *resdir;
487 {
488   int c, i;
489   struct res_entry *re;
490   struct res_entry **a;
491
492   if (resdir->entries == NULL)
493     return resdir;
494
495   c = 0;
496   for (re = resdir->entries; re != NULL; re = re->next)
497     ++c;
498
499   /* This is a recursive routine, so using xmalloc is probably better
500      than alloca.  */
501   a = (struct res_entry **) xmalloc (c * sizeof (struct res_entry *));
502
503   for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
504     a[i] = re;
505
506   qsort (a, c, sizeof (struct res_entry *), cmp_res_entry);
507
508   resdir->entries = a[0];
509   for (i = 0; i < c - 1; i++)
510     a[i]->next = a[i + 1];
511   a[i]->next = NULL;
512
513   free (a);
514
515   /* Now sort the subdirectories.  */
516
517   for (re = resdir->entries; re != NULL; re = re->next)
518     if (re->subdir)
519       re->u.dir = sort_resources (re->u.dir);
520
521   return resdir;
522 }
523 \f
524 /* Return whether the dialog resource DIALOG is a DIALOG or a
525    DIALOGEX.  */
526
527 int
528 extended_dialog (dialog)
529      const struct dialog *dialog;
530 {
531   const struct dialog_control *c;
532
533   if (dialog->ex != NULL)
534     return 1;
535
536   for (c = dialog->controls; c != NULL; c = c->next)
537     if (c->data != NULL || c->help != 0)
538       return 1;
539
540   return 0;
541 }
542
543 /* Return whether MENUITEMS are a MENU or a MENUEX.  */
544
545 int
546 extended_menu (menu)
547      const struct menu *menu;
548 {
549   return extended_menuitems (menu->items);
550 }
551
552 static int
553 extended_menuitems (menuitems)
554      const struct menuitem *menuitems;
555 {
556   const struct menuitem *mi;
557
558   for (mi = menuitems; mi != NULL; mi = mi->next)
559     {
560       if (mi->help != 0 || mi->state != 0)
561         return 1;
562       if (mi->popup != NULL && mi->id != 0)
563         return 1;
564       if ((mi->type
565            & ~ (MENUITEM_CHECKED
566                 | MENUITEM_GRAYED
567                 | MENUITEM_HELP
568                 | MENUITEM_INACTIVE
569                 | MENUITEM_MENUBARBREAK
570                 | MENUITEM_MENUBREAK))
571           != 0)
572         return 1;
573       if (mi->popup != NULL)
574         {
575           if (extended_menuitems (mi->popup))
576             return 1;
577         }
578     }
579
580   return 0;
581 }
582 \f
583 /* Convert a string to a format type, or exit if it can't be done.  */
584
585 static enum res_format
586 format_from_name (name)
587      const char *name;
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
595   if (m->name == NULL)
596     {
597       non_fatal (_("unknown format type `%s'"), name);
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
611 static enum res_format
612 format_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.  */
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.  */
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.  */
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)))
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
692 static void
693 usage (stream, status)
694      FILE *stream;
695      int status;
696 {
697   fprintf (stream, _("Usage: %s [option(s)] [input-file] [output-file]\n"),
698            program_name);
699   fprintf (stream, _(" The options are:\n\
700   -i --input=<file>            Name input file\n\
701   -o --output=<file>           Name output file\n\
702   -I --input-format=<format>   Specify input format\n\
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\
706      --include-dir=<dir>       Include directory when preprocessing rc file\n\
707   -D --define <sym>[=<val>]    Define SYM when preprocessing rc file\n\
708   -U --undefine <sym>          Undefine SYM when preprocessing rc file\n\
709   -v --verbose                 Verbose - tells you what it's doing\n\
710      --language=<val>          Set language when reading rc file\n\
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"));
714 #ifdef YYDEBUG
715   fprintf (stream, _("\
716      --yydebug                 Turn on parser debugging\n"));
717 #endif
718   fprintf (stream, _("\
719   -r                           Ignored for compatibility with rc\n\
720   -h --help                    Print this help message\n\
721   -V --version                 Print version information\n"));
722   fprintf (stream, _("\
723 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
724 extension if not specified.  A single file name is an input file.\n\
725 No input-file is stdin, default rc.  No output-file is stdout, default rc.\n"));
726
727   list_supported_targets (program_name, stream);
728
729   if (status == 0)
730     fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
731
732   exit (status);
733 }
734
735 /* Quote characters that will confuse the shell when we run the preprocessor.  */
736
737 static const char *
738 quot (string)
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
765 /* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes.  */
766 int main PARAMS ((int, char **));
767
768 /* The main function.  */
769
770 int
771 main (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;
779   enum res_format output_format;
780   char *target;
781   char *preprocessor;
782   char *preprocargs;
783   const char *quotedarg;
784   int language;
785   struct res_directory *resources;
786   int use_temp_file;
787
788 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
789   setlocale (LC_MESSAGES, "");
790 #endif
791 #if defined (HAVE_SETLOCALE)
792   setlocale (LC_CTYPE, "");
793 #endif
794   bindtextdomain (PACKAGE, LOCALEDIR);
795   textdomain (PACKAGE);
796
797   program_name = argv[0];
798   xmalloc_set_program_name (program_name);
799
800   bfd_init ();
801   set_default_bfd_target ();
802
803   res_init ();
804
805   input_filename = NULL;
806   output_filename = NULL;
807   input_format = RES_FORMAT_UNKNOWN;
808   output_format = RES_FORMAT_UNKNOWN;
809   target = NULL;
810   preprocessor = NULL;
811   preprocargs = NULL;
812   language = 0x409;   /* LANG_ENGLISH, SUBLANG_ENGLISH_US.  */
813   use_temp_file = 0;
814
815   while ((c = getopt_long (argc, argv, "i:l:o:I:O:F:D:U:rhHvV", long_options,
816                            (int *) 0)) != EOF)
817     {
818       switch (c)
819         {
820         case 'i':
821           input_filename = optarg;
822           break;
823
824         case 'o':
825           output_filename = optarg;
826           break;
827
828         case 'I':
829           input_format = format_from_name (optarg);
830           break;
831
832         case 'O':
833           output_format = format_from_name (optarg);
834           break;
835
836         case 'F':
837           target = optarg;
838           break;
839
840         case OPTION_PREPROCESSOR:
841           preprocessor = optarg;
842           break;
843
844         case 'D':
845         case 'U':
846           if (preprocargs == NULL)
847             {
848               quotedarg = quot (optarg);
849               preprocargs = xmalloc (strlen (quotedarg) + 3);
850               sprintf (preprocargs, "-%c%s", c, quotedarg);
851             }
852           else
853             {
854               char *n;
855
856               quotedarg = quot (optarg);
857               n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
858               sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
859               free (preprocargs);
860               preprocargs = n;
861             }
862           break;
863
864         case 'r':
865           /* Ignored for compatibility with rc.  */
866           break;
867
868         case 'v':
869           verbose ++;
870           break;
871
872         case OPTION_INCLUDE_DIR:
873           if (preprocargs == NULL)
874             {
875               quotedarg = quot (optarg);
876               preprocargs = xmalloc (strlen (quotedarg) + 3);
877               sprintf (preprocargs, "-I%s", quotedarg);
878             }
879           else
880             {
881               char *n;
882
883               quotedarg = quot (optarg);
884               n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
885               sprintf (n, "%s -I%s", preprocargs, quotedarg);
886               free (preprocargs);
887               preprocargs = n;
888             }
889
890           {
891             struct include_dir *n, **pp;
892
893             n = (struct include_dir *) xmalloc (sizeof *n);
894             n->next = NULL;
895             n->dir = optarg;
896
897             for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
898               ;
899             *pp = n;
900           }
901
902           break;
903
904         case 'l':
905           language = strtol (optarg, (char **) NULL, 16);
906           break;
907
908         case OPTION_USE_TEMP_FILE:
909           use_temp_file = 1;
910           break;
911
912         case OPTION_NO_USE_TEMP_FILE:
913           use_temp_file = 0;
914           break;
915
916 #ifdef YYDEBUG
917         case OPTION_YYDEBUG:
918           yydebug = 1;
919           break;
920 #endif
921
922         case 'h':
923         case 'H':
924           usage (stdout, 0);
925           break;
926
927         case 'V':
928           print_version ("windres");
929           break;
930
931         default:
932           usage (stderr, 1);
933           break;
934         }
935     }
936
937   if (input_filename == NULL && optind < argc)
938     {
939       input_filename = argv[optind];
940       ++optind;
941     }
942
943   if (output_filename == NULL && optind < argc)
944     {
945       output_filename = argv[optind];
946       ++optind;
947     }
948
949   if (argc != optind)
950     usage (stderr, 1);
951
952   if (input_format == RES_FORMAT_UNKNOWN)
953     {
954       if (input_filename == NULL)
955         input_format = RES_FORMAT_RC;
956       else
957         input_format = format_from_filename (input_filename, 1);
958     }
959
960   if (output_format == RES_FORMAT_UNKNOWN)
961     {
962       if (output_filename == NULL)
963         output_format = RES_FORMAT_RC;
964       else
965         output_format = format_from_filename (output_filename, 0);
966     }
967
968   /* Read the input file.  */
969   switch (input_format)
970     {
971     default:
972       abort ();
973     case RES_FORMAT_RC:
974       resources = read_rc_file (input_filename, preprocessor, preprocargs,
975                                 language, use_temp_file);
976       break;
977     case RES_FORMAT_RES:
978       resources = read_res_file (input_filename);
979       break;
980     case RES_FORMAT_COFF:
981       resources = read_coff_rsrc (input_filename, target);
982       break;
983     }
984
985   if (resources == NULL)
986     fatal (_("no resources"));
987
988   /* Sort the resources.  This is required for COFF, convenient for
989      rc, and unimportant for res.  */
990   resources = sort_resources (resources);
991
992   /* Write the output file.  */
993   reswr_init ();
994
995   switch (output_format)
996     {
997     default:
998       abort ();
999     case RES_FORMAT_RC:
1000       write_rc_file (output_filename, resources);
1001       break;
1002     case RES_FORMAT_RES:
1003       write_res_file (output_filename, resources);
1004       break;
1005     case RES_FORMAT_COFF:
1006       write_coff_file (output_filename, target, resources);
1007       break;
1008     }
1009
1010   xexit (0);
1011   return 0;
1012 }
1013