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
53int verbose = 0;
54
55/* An enumeration of format types.  */
56
57enum 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
71struct format_map
72{
73  const char *name;
74  enum res_format format;
75};
76
77/* A mapping between names and format types.  */
78
79static 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
89static 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
101struct include_dir
102{
103  struct include_dir *next;
104  char *dir;
105};
106
107static struct include_dir *include_dirs;
108
109/* Static functions.  */
110
111static void res_init (void);
112static int extended_menuitems (const struct menuitem *);
113static enum res_format format_from_name (const char *, int);
114static enum res_format format_from_filename (const char *, int);
115static void usage (FILE *, int);
116static int cmp_res_entry (const void *, const void *);
117static struct res_directory *sort_resources (struct res_directory *);
118static void reswr_init (void);
119static const char * quot (const char *);
120
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
129static struct obstack res_obstack;
130
131/* Initialize the resource building obstack.  */
132
133static void
134res_init (void)
135{
136  obstack_init (&res_obstack);
137}
138
139/* Allocate space on the resource building obstack.  */
140
141void *
142res_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
150static struct obstack reswr_obstack;
151
152/* Initialize the resource writing obstack.  */
153
154static void
155reswr_init (void)
156{
157  obstack_init (&reswr_obstack);
158}
159
160/* Allocate space on the resource writing obstack.  */
161
162void *
163reswr_alloc (size_t bytes)
164{
165  return (void *) obstack_alloc (&reswr_obstack, bytes);
166}
167
168/* Open a file using the include directory search list.  */
169
170FILE *
171open_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
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
214int
215res_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
262void
263res_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
279void
280res_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
294void
295res_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
309struct res_resource *
310define_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
407struct res_resource *
408define_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
423static int
424cmp_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
435static struct res_directory *
436sort_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
474/* Return whether the dialog resource DIALOG is a DIALOG or a
475   DIALOGEX.  */
476
477int
478extended_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
494int
495extended_menu (const struct menu *menu)
496{
497  return extended_menuitems (menu->items);
498}
499
500static int
501extended_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
530/* Convert a string to a format type, or exit if it can't be done.  */
531
532static enum res_format
533format_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
557static enum res_format
558format_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
636static void
637usage (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  @<file>                      Read options from <file>\n\
663  -h --help                    Print this help message\n\
664  -V --version                 Print version information\n"));
665  fprintf (stream, _("\
666FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
667extension if not specified.  A single file name is an input file.\n\
668No input-file is stdin, default rc.  No output-file is stdout, default rc.\n"));
669
670  list_supported_targets (program_name, stream);
671
672  if (status == 0)
673    fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
674
675  exit (status);
676}
677
678/* Quote characters that will confuse the shell when we run the preprocessor.  */
679
680static const char *
681quot (const char *string)
682{
683  static char *buf = 0;
684  static int buflen = 0;
685  int slen = strlen (string);
686  const char *src;
687  char *dest;
688
689  if ((buflen < slen * 2 + 2) || !buf)
690    {
691      buflen = slen * 2 + 2;
692      if (buf)
693	free (buf);
694      buf = (char *) xmalloc (buflen);
695    }
696
697  for (src=string, dest=buf; *src; src++, dest++)
698    {
699      if (*src == '(' || *src == ')' || *src == ' ')
700	*dest++ = '\\';
701      *dest = *src;
702    }
703  *dest = 0;
704  return buf;
705}
706
707/* Long options.  */
708
709/* 150 isn't special; it's just an arbitrary non-ASCII char value.  */
710
711#define OPTION_PREPROCESSOR	150
712#define OPTION_USE_TEMP_FILE	(OPTION_PREPROCESSOR + 1)
713#define OPTION_NO_USE_TEMP_FILE	(OPTION_USE_TEMP_FILE + 1)
714#define OPTION_YYDEBUG		(OPTION_NO_USE_TEMP_FILE + 1)
715
716static const struct option long_options[] =
717{
718  {"input", required_argument, 0, 'i'},
719  {"output", required_argument, 0, 'o'},
720  {"input-format", required_argument, 0, 'J'},
721  {"output-format", required_argument, 0, 'O'},
722  {"target", required_argument, 0, 'F'},
723  {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
724  {"include-dir", required_argument, 0, 'I'},
725  {"define", required_argument, 0, 'D'},
726  {"undefine", required_argument, 0, 'U'},
727  {"verbose", no_argument, 0, 'v'},
728  {"language", required_argument, 0, 'l'},
729  {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
730  {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
731  {"yydebug", no_argument, 0, OPTION_YYDEBUG},
732  {"version", no_argument, 0, 'V'},
733  {"help", no_argument, 0, 'h'},
734  {0, no_argument, 0, 0}
735};
736
737/* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes.  */
738int main (int, char **);
739
740/* The main function.  */
741
742int
743main (int argc, char **argv)
744{
745  int c;
746  char *input_filename;
747  char *output_filename;
748  enum res_format input_format;
749  enum res_format input_format_tmp;
750  enum res_format output_format;
751  char *target;
752  char *preprocessor;
753  char *preprocargs;
754  const char *quotedarg;
755  int language;
756  struct res_directory *resources;
757  int use_temp_file;
758
759#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
760  setlocale (LC_MESSAGES, "");
761#endif
762#if defined (HAVE_SETLOCALE)
763  setlocale (LC_CTYPE, "");
764#endif
765  bindtextdomain (PACKAGE, LOCALEDIR);
766  textdomain (PACKAGE);
767
768  program_name = argv[0];
769  xmalloc_set_program_name (program_name);
770
771  expandargv (&argc, &argv);
772
773  bfd_init ();
774  set_default_bfd_target ();
775
776  res_init ();
777
778  input_filename = NULL;
779  output_filename = NULL;
780  input_format = RES_FORMAT_UNKNOWN;
781  output_format = RES_FORMAT_UNKNOWN;
782  target = NULL;
783  preprocessor = NULL;
784  preprocargs = NULL;
785  language = 0x409;   /* LANG_ENGLISH, SUBLANG_ENGLISH_US.  */
786  use_temp_file = 0;
787
788  while ((c = getopt_long (argc, argv, "f:i:l:o:I:J:O:F:D:U:rhHvV", long_options,
789			   (int *) 0)) != EOF)
790    {
791      switch (c)
792	{
793	case 'i':
794	  input_filename = optarg;
795	  break;
796
797	case 'f':
798	  /* For compatibility with rc we accept "-fo <name>" as being the
799	     equivalent of "-o <name>".  We do not advertise this fact
800	     though, as we do not want users to use non-GNU like command
801	     line switches.  */
802	  if (*optarg != 'o')
803	    fatal (_("invalid option -f\n"));
804	  optarg++;
805	  if (* optarg == 0)
806	    {
807	      if (optind == argc)
808		fatal (_("No filename following the -fo option.\n"));
809	      optarg = argv [optind++];
810	    }
811	  /* Fall through.  */
812
813	case 'o':
814	  output_filename = optarg;
815	  break;
816
817	case 'J':
818	  input_format = format_from_name (optarg, 1);
819	  break;
820
821	case 'O':
822	  output_format = format_from_name (optarg, 1);
823	  break;
824
825	case 'F':
826	  target = optarg;
827	  break;
828
829	case OPTION_PREPROCESSOR:
830	  preprocessor = optarg;
831	  break;
832
833	case 'D':
834	case 'U':
835	  if (preprocargs == NULL)
836	    {
837	      quotedarg = quot (optarg);
838	      preprocargs = xmalloc (strlen (quotedarg) + 3);
839	      sprintf (preprocargs, "-%c%s", c, quotedarg);
840	    }
841	  else
842	    {
843	      char *n;
844
845	      quotedarg = quot (optarg);
846	      n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
847	      sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
848	      free (preprocargs);
849	      preprocargs = n;
850	    }
851	  break;
852
853	case 'r':
854	  /* Ignored for compatibility with rc.  */
855	  break;
856
857	case 'v':
858	  verbose ++;
859	  break;
860
861	case 'I':
862	  /* For backward compatibility, should be removed in the future.  */
863	  input_format_tmp = format_from_name (optarg, 0);
864	  if (input_format_tmp != RES_FORMAT_UNKNOWN)
865	    {
866	      fprintf (stderr, _("Option -I is deprecated for setting the input format, please use -J instead.\n"));
867	      input_format = input_format_tmp;
868	      break;
869	    }
870
871	  if (preprocargs == NULL)
872	    {
873	      quotedarg = quot (optarg);
874	      preprocargs = xmalloc (strlen (quotedarg) + 3);
875	      sprintf (preprocargs, "-I%s", quotedarg);
876	    }
877	  else
878	    {
879	      char *n;
880
881	      quotedarg = quot (optarg);
882	      n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
883	      sprintf (n, "%s -I%s", preprocargs, quotedarg);
884	      free (preprocargs);
885	      preprocargs = n;
886	    }
887
888	  {
889	    struct include_dir *n, **pp;
890
891	    n = (struct include_dir *) xmalloc (sizeof *n);
892	    n->next = NULL;
893	    n->dir = optarg;
894
895	    for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
896	      ;
897	    *pp = n;
898	  }
899
900	  break;
901
902	case 'l':
903	  language = strtol (optarg, (char **) NULL, 16);
904	  break;
905
906	case OPTION_USE_TEMP_FILE:
907	  use_temp_file = 1;
908	  break;
909
910	case OPTION_NO_USE_TEMP_FILE:
911	  use_temp_file = 0;
912	  break;
913
914#ifdef YYDEBUG
915	case OPTION_YYDEBUG:
916	  yydebug = 1;
917	  break;
918#endif
919
920	case 'h':
921	case 'H':
922	  usage (stdout, 0);
923	  break;
924
925	case 'V':
926	  print_version ("windres");
927	  break;
928
929	default:
930	  usage (stderr, 1);
931	  break;
932	}
933    }
934
935  if (input_filename == NULL && optind < argc)
936    {
937      input_filename = argv[optind];
938      ++optind;
939    }
940
941  if (output_filename == NULL && optind < argc)
942    {
943      output_filename = argv[optind];
944      ++optind;
945    }
946
947  if (argc != optind)
948    usage (stderr, 1);
949
950  if (input_format == RES_FORMAT_UNKNOWN)
951    {
952      if (input_filename == NULL)
953	input_format = RES_FORMAT_RC;
954      else
955	input_format = format_from_filename (input_filename, 1);
956    }
957
958  if (output_format == RES_FORMAT_UNKNOWN)
959    {
960      if (output_filename == NULL)
961	output_format = RES_FORMAT_RC;
962      else
963	output_format = format_from_filename (output_filename, 0);
964    }
965
966  /* Read the input file.  */
967  switch (input_format)
968    {
969    default:
970      abort ();
971    case RES_FORMAT_RC:
972      resources = read_rc_file (input_filename, preprocessor, preprocargs,
973				language, use_temp_file);
974      break;
975    case RES_FORMAT_RES:
976      resources = read_res_file (input_filename);
977      break;
978    case RES_FORMAT_COFF:
979      resources = read_coff_rsrc (input_filename, target);
980      break;
981    }
982
983  if (resources == NULL)
984    fatal (_("no resources"));
985
986  /* Sort the resources.  This is required for COFF, convenient for
987     rc, and unimportant for res.  */
988  resources = sort_resources (resources);
989
990  /* Write the output file.  */
991  reswr_init ();
992
993  switch (output_format)
994    {
995    default:
996      abort ();
997    case RES_FORMAT_RC:
998      write_rc_file (output_filename, resources);
999      break;
1000    case RES_FORMAT_RES:
1001      write_res_file (output_filename, resources);
1002      break;
1003    case RES_FORMAT_COFF:
1004      write_coff_file (output_filename, target, resources);
1005      break;
1006    }
1007
1008  xexit (0);
1009  return 0;
1010}
1011