* dlltool.c (main): Fix typo.
[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, 2004, 2005
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., 51 Franklin Street - Fifth Floor, Boston, MA
21    02110-1301, 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 "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"
50
51 /* Used by resrc.c at least.  */
52
53 int verbose = 0;
54
55 /* An enumeration of format types.  */
56
57 enum res_format
58 {
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
67 };
68
69 /* A structure used to map between format types and strings.  */
70
71 struct format_map
72 {
73   const char *name;
74   enum res_format format;
75 };
76
77 /* A mapping between names and format types.  */
78
79 static const struct format_map format_names[] =
80 {
81   { "rc", RES_FORMAT_RC },
82   { "res", RES_FORMAT_RES },
83   { "coff", RES_FORMAT_COFF },
84   { NULL, RES_FORMAT_UNKNOWN }
85 };
86
87 /* A mapping from file extensions to format types.  */
88
89 static const struct format_map format_fileexts[] =
90 {
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 }
97 };
98
99 /* A list of include directories.  */
100
101 struct include_dir
102 {
103   struct include_dir *next;
104   char *dir;
105 };
106
107 static struct include_dir *include_dirs;
108
109 /* Static functions.  */
110
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 *);
120 \f
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.  */
123
124 #define obstack_chunk_alloc xmalloc
125 #define obstack_chunk_free free
126
127 /* The resource building obstack.  */
128
129 static struct obstack res_obstack;
130
131 /* Initialize the resource building obstack.  */
132
133 static void
134 res_init (void)
135 {
136   obstack_init (&res_obstack);
137 }
138
139 /* Allocate space on the resource building obstack.  */
140
141 void *
142 res_alloc (size_t bytes)
143 {
144   return (void *) obstack_alloc (&res_obstack, bytes);
145 }
146
147 /* We also use an obstack to save memory used while writing out a set
148    of resources.  */
149
150 static struct obstack reswr_obstack;
151
152 /* Initialize the resource writing obstack.  */
153
154 static void
155 reswr_init (void)
156 {
157   obstack_init (&reswr_obstack);
158 }
159
160 /* Allocate space on the resource writing obstack.  */
161
162 void *
163 reswr_alloc (size_t bytes)
164 {
165   return (void *) obstack_alloc (&reswr_obstack, bytes);
166 }
167 \f
168 /* Open a file using the include directory search list.  */
169
170 FILE *
171 open_file_search (const char *filename, const char *mode, const char *errmsg,
172                   char **real_filename)
173 {
174   FILE *e;
175   struct include_dir *d;
176
177   e = fopen (filename, mode);
178   if (e != NULL)
179     {
180       *real_filename = xstrdup (filename);
181       return e;
182     }
183
184   if (errno == ENOENT)
185     {
186       for (d = include_dirs; d != NULL; d = d->next)
187         {
188           char *n;
189
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)
194             {
195               *real_filename = n;
196               return e;
197             }
198
199           if (errno != ENOENT)
200             break;
201         }
202     }
203
204   fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
205
206   /* Return a value to avoid a compiler warning.  */
207   return NULL;
208 }
209 \f
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.  */
213
214 int
215 res_id_cmp (struct res_id a, struct res_id b)
216 {
217   if (! a.named)
218     {
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;
227     }
228   else
229     {
230       unichar *as, *ase, *bs, *bse;
231
232       if (! b.named)
233         return -1;
234
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;
239
240       while (as < ase)
241         {
242           int i;
243
244           if (bs >= bse)
245             return 1;
246           i = (int) *as - (int) *bs;
247           if (i != 0)
248             return i;
249           ++as;
250           ++bs;
251         }
252
253       if (bs < bse)
254         return -1;
255
256       return 0;
257     }
258 }
259
260 /* Print a resource ID.  */
261
262 void
263 res_id_print (FILE *stream, struct res_id id, int quote)
264 {
265   if (! id.named)
266     fprintf (stream, "%lu", id.u.id);
267   else
268     {
269       if (quote)
270         putc ('"', stream);
271       unicode_print (stream, id.u.n.name, id.u.n.length);
272       if (quote)
273         putc ('"', stream);
274     }
275 }
276
277 /* Print a list of resource ID's.  */
278
279 void
280 res_ids_print (FILE *stream, int cids, const struct res_id *ids)
281 {
282   int i;
283
284   for (i = 0; i < cids; i++)
285     {
286       res_id_print (stream, ids[i], 1);
287       if (i + 1 < cids)
288         fprintf (stream, ": ");
289     }
290 }
291
292 /* Convert an ASCII string to a resource ID.  */
293
294 void
295 res_string_to_id (struct res_id *res_id, const char *string)
296 {
297   res_id->named = 1;
298   unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
299 }
300
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.  */
308
309 struct res_resource *
310 define_resource (struct res_directory **resources, int cids,
311                  const struct res_id *ids, int dupok)
312 {
313   struct res_entry *re = NULL;
314   int i;
315
316   assert (cids > 0);
317   for (i = 0; i < cids; i++)
318     {
319       struct res_entry **pp;
320
321       if (*resources == NULL)
322         {
323           static unsigned long timeval;
324
325           /* Use the same timestamp for every resource created in a
326              single run.  */
327           if (timeval == 0)
328             timeval = time (NULL);
329
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;
337         }
338
339       for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
340         if (res_id_cmp ((*pp)->id, ids[i]) == 0)
341           break;
342
343       if (*pp != NULL)
344         re = *pp;
345       else
346         {
347           re = (struct res_entry *) res_alloc (sizeof *re);
348           re->next = NULL;
349           re->id = ids[i];
350           if ((i + 1) < cids)
351             {
352               re->subdir = 1;
353               re->u.dir = NULL;
354             }
355           else
356             {
357               re->subdir = 0;
358               re->u.res = NULL;
359             }
360
361           *pp = re;
362         }
363
364       if ((i + 1) < cids)
365         {
366           if (! re->subdir)
367             {
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);
372             }
373
374           resources = &re->u.dir;
375         }
376     }
377
378   if (re->subdir)
379     {
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);
384     }
385
386   if (re->u.res != NULL)
387     {
388       if (dupok)
389         return re->u.res;
390
391       fprintf (stderr, _("%s: warning: "), program_name);
392       res_ids_print (stderr, cids, ids);
393       fprintf (stderr, _(": duplicate value\n"));
394     }
395
396   re->u.res = ((struct res_resource *)
397                res_alloc (sizeof (struct res_resource)));
398   memset (re->u.res, 0, sizeof (struct res_resource));
399
400   re->u.res->type = RES_TYPE_UNINITIALIZED;
401   return re->u.res;
402 }
403
404 /* Define a standard resource.  This is a version of define_resource
405    that just takes type, name, and language arguments.  */
406
407 struct res_resource *
408 define_standard_resource (struct res_directory **resources, int type,
409                           struct res_id name, int language, int dupok)
410 {
411   struct res_id a[3];
412
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);
419 }
420
421 /* Comparison routine for resource sorting.  */
422
423 static int
424 cmp_res_entry (const void *p1, const void *p2)
425 {
426   const struct res_entry **re1, **re2;
427
428   re1 = (const struct res_entry **) p1;
429   re2 = (const struct res_entry **) p2;
430   return res_id_cmp ((*re1)->id, (*re2)->id);
431 }
432
433 /* Sort the resources.  */
434
435 static struct res_directory *
436 sort_resources (struct res_directory *resdir)
437 {
438   int c, i;
439   struct res_entry *re;
440   struct res_entry **a;
441
442   if (resdir->entries == NULL)
443     return resdir;
444
445   c = 0;
446   for (re = resdir->entries; re != NULL; re = re->next)
447     ++c;
448
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 *));
452
453   for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
454     a[i] = re;
455
456   qsort (a, c, sizeof (struct res_entry *), cmp_res_entry);
457
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;
462
463   free (a);
464
465   /* Now sort the subdirectories.  */
466
467   for (re = resdir->entries; re != NULL; re = re->next)
468     if (re->subdir)
469       re->u.dir = sort_resources (re->u.dir);
470
471   return resdir;
472 }
473 \f
474 /* Return whether the dialog resource DIALOG is a DIALOG or a
475    DIALOGEX.  */
476
477 int
478 extended_dialog (const struct dialog *dialog)
479 {
480   const struct dialog_control *c;
481
482   if (dialog->ex != NULL)
483     return 1;
484
485   for (c = dialog->controls; c != NULL; c = c->next)
486     if (c->data != NULL || c->help != 0)
487       return 1;
488
489   return 0;
490 }
491
492 /* Return whether MENUITEMS are a MENU or a MENUEX.  */
493
494 int
495 extended_menu (const struct menu *menu)
496 {
497   return extended_menuitems (menu->items);
498 }
499
500 static int
501 extended_menuitems (const struct menuitem *menuitems)
502 {
503   const struct menuitem *mi;
504
505   for (mi = menuitems; mi != NULL; mi = mi->next)
506     {
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)
521         {
522           if (extended_menuitems (mi->popup))
523             return 1;
524         }
525     }
526
527   return 0;
528 }
529 \f
530 /* Convert a string to a format type, or exit if it can't be done.  */
531
532 static enum res_format
533 format_from_name (const char *name, int exit_on_error)
534 {
535   const struct format_map *m;
536
537   for (m = format_names; m->name != NULL; m++)
538     if (strcasecmp (m->name, name) == 0)
539       break;
540
541   if (m->name == NULL && exit_on_error)
542     {
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);
549     }
550
551   return m->format;
552 }
553
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.  */
556
557 static enum res_format
558 format_from_filename (const char *filename, int input)
559 {
560   const char *ext;
561   FILE *e;
562   unsigned char b1, b2, b3, b4, b5;
563   int magic;
564
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)
569     {
570       const struct format_map *m;
571
572       ++ext;
573       for (m = format_fileexts; m->name != NULL; m++)
574         if (strcasecmp (m->name, ext) == 0)
575           return m->format;
576     }
577
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;
582
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));
588
589   b1 = getc (e);
590   b2 = getc (e);
591   b3 = getc (e);
592   b4 = getc (e);
593   b5 = getc (e);
594
595   fclose (e);
596
597   /* A PE executable starts with 0x4d 0x5a.  */
598   if (b1 == 0x4d && b2 == 0x5a)
599     return RES_FORMAT_COFF;
600
601   /* A COFF .o file starts with a COFF magic number.  */
602   magic = (b2 << 8) | b1;
603   switch (magic)
604     {
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;
612     }
613
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;
617
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;
625
626   /* Otherwise, we give up.  */
627   fatal (_("can not determine type of file `%s'; use the -J option"),
628          filename);
629
630   /* Return something to silence the compiler warning.  */
631   return RES_FORMAT_UNKNOWN;
632 }
633
634 /* Print a usage message and exit.  */
635
636 static void
637 usage (FILE *stream, int status)
638 {
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"));
668
669   list_supported_targets (program_name, stream);
670
671   if (status == 0)
672     fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
673
674   exit (status);
675 }
676
677 /* Quote characters that will confuse the shell when we run the preprocessor.  */
678
679 static const char *
680 quot (const char *string)
681 {
682   static char *buf = 0;
683   static int buflen = 0;
684   int slen = strlen (string);
685   const char *src;
686   char *dest;
687
688   if ((buflen < slen * 2 + 2) || !buf)
689     {
690       buflen = slen * 2 + 2;
691       if (buf)
692         free (buf);
693       buf = (char *) xmalloc (buflen);
694     }
695
696   for (src=string, dest=buf; *src; src++, dest++)
697     {
698       if (*src == '(' || *src == ')' || *src == ' ')
699         *dest++ = '\\';
700       *dest = *src;
701     }
702   *dest = 0;
703   return buf;
704 }
705
706 /* Long options.  */
707
708 /* 150 isn't special; it's just an arbitrary non-ASCII char value.  */
709
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)
714
715 static const struct option long_options[] =
716 {
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}
734 };
735
736 /* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes.  */
737 int main (int, char **);
738
739 /* The main function.  */
740
741 int
742 main (int argc, char **argv)
743 {
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;
757
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);
766
767   program_name = argv[0];
768   xmalloc_set_program_name (program_name);
769
770   expandargv (&argc, &argv);
771
772   bfd_init ();
773   set_default_bfd_target ();
774
775   res_init ();
776
777   input_filename = NULL;
778   output_filename = NULL;
779   input_format = RES_FORMAT_UNKNOWN;
780   output_format = RES_FORMAT_UNKNOWN;
781   target = NULL;
782   preprocessor = NULL;
783   preprocargs = NULL;
784   language = 0x409;   /* LANG_ENGLISH, SUBLANG_ENGLISH_US.  */
785   use_temp_file = 0;
786
787   while ((c = getopt_long (argc, argv, "f:i:l:o:I:J:O:F:D:U:rhHvV", long_options,
788                            (int *) 0)) != EOF)
789     {
790       switch (c)
791         {
792         case 'i':
793           input_filename = optarg;
794           break;
795
796         case 'f':
797           /* For compatibility with rc we accept "-fo <name>" as being the
798              equivalent of "-o <name>".  We do not advertise this fact
799              though, as we do not want users to use non-GNU like command
800              line switches.  */
801           if (*optarg != 'o')
802             fatal (_("invalid option -f\n"));
803           optarg++;
804           if (* optarg == 0)
805             {
806               if (optind == argc)
807                 fatal (_("No filename following the -fo option.\n"));
808               optarg = argv [optind++];
809             }
810           /* Fall through.  */
811
812         case 'o':
813           output_filename = optarg;
814           break;
815
816         case 'J':
817           input_format = format_from_name (optarg, 1);
818           break;
819
820         case 'O':
821           output_format = format_from_name (optarg, 1);
822           break;
823
824         case 'F':
825           target = optarg;
826           break;
827
828         case OPTION_PREPROCESSOR:
829           preprocessor = optarg;
830           break;
831
832         case 'D':
833         case 'U':
834           if (preprocargs == NULL)
835             {
836               quotedarg = quot (optarg);
837               preprocargs = xmalloc (strlen (quotedarg) + 3);
838               sprintf (preprocargs, "-%c%s", c, quotedarg);
839             }
840           else
841             {
842               char *n;
843
844               quotedarg = quot (optarg);
845               n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
846               sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
847               free (preprocargs);
848               preprocargs = n;
849             }
850           break;
851
852         case 'r':
853           /* Ignored for compatibility with rc.  */
854           break;
855
856         case 'v':
857           verbose ++;
858           break;
859
860         case 'I':
861           /* For backward compatibility, should be removed in the future.  */
862           input_format_tmp = format_from_name (optarg, 0);
863           if (input_format_tmp != RES_FORMAT_UNKNOWN)
864             {
865               fprintf (stderr, _("Option -I is deprecated for setting the input format, please use -J instead.\n"));
866               input_format = input_format_tmp;
867               break;
868             }
869
870           if (preprocargs == NULL)
871             {
872               quotedarg = quot (optarg);
873               preprocargs = xmalloc (strlen (quotedarg) + 3);
874               sprintf (preprocargs, "-I%s", quotedarg);
875             }
876           else
877             {
878               char *n;
879
880               quotedarg = quot (optarg);
881               n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
882               sprintf (n, "%s -I%s", preprocargs, quotedarg);
883               free (preprocargs);
884               preprocargs = n;
885             }
886
887           {
888             struct include_dir *n, **pp;
889
890             n = (struct include_dir *) xmalloc (sizeof *n);
891             n->next = NULL;
892             n->dir = optarg;
893
894             for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
895               ;
896             *pp = n;
897           }
898
899           break;
900
901         case 'l':
902           language = strtol (optarg, (char **) NULL, 16);
903           break;
904
905         case OPTION_USE_TEMP_FILE:
906           use_temp_file = 1;
907           break;
908
909         case OPTION_NO_USE_TEMP_FILE:
910           use_temp_file = 0;
911           break;
912
913 #ifdef YYDEBUG
914         case OPTION_YYDEBUG:
915           yydebug = 1;
916           break;
917 #endif
918
919         case 'h':
920         case 'H':
921           usage (stdout, 0);
922           break;
923
924         case 'V':
925           print_version ("windres");
926           break;
927
928         default:
929           usage (stderr, 1);
930           break;
931         }
932     }
933
934   if (input_filename == NULL && optind < argc)
935     {
936       input_filename = argv[optind];
937       ++optind;
938     }
939
940   if (output_filename == NULL && optind < argc)
941     {
942       output_filename = argv[optind];
943       ++optind;
944     }
945
946   if (argc != optind)
947     usage (stderr, 1);
948
949   if (input_format == RES_FORMAT_UNKNOWN)
950     {
951       if (input_filename == NULL)
952         input_format = RES_FORMAT_RC;
953       else
954         input_format = format_from_filename (input_filename, 1);
955     }
956
957   if (output_format == RES_FORMAT_UNKNOWN)
958     {
959       if (output_filename == NULL)
960         output_format = RES_FORMAT_RC;
961       else
962         output_format = format_from_filename (output_filename, 0);
963     }
964
965   /* Read the input file.  */
966   switch (input_format)
967     {
968     default:
969       abort ();
970     case RES_FORMAT_RC:
971       resources = read_rc_file (input_filename, preprocessor, preprocargs,
972                                 language, use_temp_file);
973       break;
974     case RES_FORMAT_RES:
975       resources = read_res_file (input_filename);
976       break;
977     case RES_FORMAT_COFF:
978       resources = read_coff_rsrc (input_filename, target);
979       break;
980     }
981
982   if (resources == NULL)
983     fatal (_("no resources"));
984
985   /* Sort the resources.  This is required for COFF, convenient for
986      rc, and unimportant for res.  */
987   resources = sort_resources (resources);
988
989   /* Write the output file.  */
990   reswr_init ();
991
992   switch (output_format)
993     {
994     default:
995       abort ();
996     case RES_FORMAT_RC:
997       write_rc_file (output_filename, resources);
998       break;
999     case RES_FORMAT_RES:
1000       write_res_file (output_filename, resources);
1001       break;
1002     case RES_FORMAT_COFF:
1003       write_coff_file (output_filename, target, resources);
1004       break;
1005     }
1006
1007   xexit (0);
1008   return 0;
1009 }