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 
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
res_init(void)134 res_init (void)
135 {
136   obstack_init (&res_obstack);
137 }
138 
139 /* Allocate space on the resource building obstack.  */
140 
141 void *
res_alloc(size_t bytes)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
reswr_init(void)155 reswr_init (void)
156 {
157   obstack_init (&reswr_obstack);
158 }
159 
160 /* Allocate space on the resource writing obstack.  */
161 
162 void *
reswr_alloc(size_t bytes)163 reswr_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 
170 FILE *
open_file_search(const char * filename,const char * mode,const char * errmsg,char ** real_filename)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 
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
res_id_cmp(struct res_id a,struct res_id b)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
res_id_print(FILE * stream,struct res_id id,int quote)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
res_ids_print(FILE * stream,int cids,const struct res_id * ids)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
res_string_to_id(struct res_id * res_id,const char * string)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 *
define_resource(struct res_directory ** resources,int cids,const struct res_id * ids,int dupok)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 *
define_standard_resource(struct res_directory ** resources,int type,struct res_id name,int language,int dupok)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
cmp_res_entry(const void * p1,const void * p2)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 *
sort_resources(struct res_directory * resdir)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 
474 /* Return whether the dialog resource DIALOG is a DIALOG or a
475    DIALOGEX.  */
476 
477 int
extended_dialog(const struct dialog * dialog)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
extended_menu(const struct menu * menu)495 extended_menu (const struct menu *menu)
496 {
497   return extended_menuitems (menu->items);
498 }
499 
500 static int
extended_menuitems(const struct menuitem * menuitems)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 
530 /* Convert a string to a format type, or exit if it can't be done.  */
531 
532 static enum res_format
format_from_name(const char * name,int exit_on_error)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
format_from_filename(const char * filename,int input)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
usage(FILE * stream,int status)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 *
quot(const char * string)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
main(int argc,char ** argv)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   bfd_init ();
771   set_default_bfd_target ();
772 
773   res_init ();
774 
775   input_filename = NULL;
776   output_filename = NULL;
777   input_format = RES_FORMAT_UNKNOWN;
778   output_format = RES_FORMAT_UNKNOWN;
779   target = NULL;
780   preprocessor = NULL;
781   preprocargs = NULL;
782   language = 0x409;   /* LANG_ENGLISH, SUBLANG_ENGLISH_US.  */
783   use_temp_file = 0;
784 
785   while ((c = getopt_long (argc, argv, "f:i:l:o:I:J:O:F:D:U:rhHvV", long_options,
786 			   (int *) 0)) != EOF)
787     {
788       switch (c)
789 	{
790 	case 'i':
791 	  input_filename = optarg;
792 	  break;
793 
794 	case 'f':
795 	  /* For compatibility with rc we accept "-fo <name>" as being the
796 	     equivalent of "-o <name>".  We do not advertise this fact
797 	     though, as we do not want users to use non-GNU like command
798 	     line switches.  */
799 	  if (*optarg != 'o')
800 	    fatal (_("invalid option -f\n"));
801 	  optarg++;
802 	  if (* optarg == 0)
803 	    {
804 	      if (optind == argc)
805 		fatal (_("No filename following the -fo option.\n"));
806 	      optarg = argv [optind++];
807 	    }
808 	  /* Fall through.  */
809 
810 	case 'o':
811 	  output_filename = optarg;
812 	  break;
813 
814 	case 'J':
815 	  input_format = format_from_name (optarg, 1);
816 	  break;
817 
818 	case 'O':
819 	  output_format = format_from_name (optarg, 1);
820 	  break;
821 
822 	case 'F':
823 	  target = optarg;
824 	  break;
825 
826 	case OPTION_PREPROCESSOR:
827 	  preprocessor = optarg;
828 	  break;
829 
830 	case 'D':
831 	case 'U':
832 	  if (preprocargs == NULL)
833 	    {
834 	      quotedarg = quot (optarg);
835 	      preprocargs = xmalloc (strlen (quotedarg) + 3);
836 	      sprintf (preprocargs, "-%c%s", c, quotedarg);
837 	    }
838 	  else
839 	    {
840 	      char *n;
841 
842 	      quotedarg = quot (optarg);
843 	      n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
844 	      sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
845 	      free (preprocargs);
846 	      preprocargs = n;
847 	    }
848 	  break;
849 
850 	case 'r':
851 	  /* Ignored for compatibility with rc.  */
852 	  break;
853 
854 	case 'v':
855 	  verbose ++;
856 	  break;
857 
858 	case 'I':
859 	  /* For backward compatibility, should be removed in the future.  */
860 	  input_format_tmp = format_from_name (optarg, 0);
861 	  if (input_format_tmp != RES_FORMAT_UNKNOWN)
862 	    {
863 	      fprintf (stderr, _("Option -I is deprecated for setting the input format, please use -J instead.\n"));
864 	      input_format = input_format_tmp;
865 	      break;
866 	    }
867 
868 	  if (preprocargs == NULL)
869 	    {
870 	      quotedarg = quot (optarg);
871 	      preprocargs = xmalloc (strlen (quotedarg) + 3);
872 	      sprintf (preprocargs, "-I%s", quotedarg);
873 	    }
874 	  else
875 	    {
876 	      char *n;
877 
878 	      quotedarg = quot (optarg);
879 	      n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
880 	      sprintf (n, "%s -I%s", preprocargs, quotedarg);
881 	      free (preprocargs);
882 	      preprocargs = n;
883 	    }
884 
885 	  {
886 	    struct include_dir *n, **pp;
887 
888 	    n = (struct include_dir *) xmalloc (sizeof *n);
889 	    n->next = NULL;
890 	    n->dir = optarg;
891 
892 	    for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
893 	      ;
894 	    *pp = n;
895 	  }
896 
897 	  break;
898 
899 	case 'l':
900 	  language = strtol (optarg, (char **) NULL, 16);
901 	  break;
902 
903 	case OPTION_USE_TEMP_FILE:
904 	  use_temp_file = 1;
905 	  break;
906 
907 	case OPTION_NO_USE_TEMP_FILE:
908 	  use_temp_file = 0;
909 	  break;
910 
911 #ifdef YYDEBUG
912 	case OPTION_YYDEBUG:
913 	  yydebug = 1;
914 	  break;
915 #endif
916 
917 	case 'h':
918 	case 'H':
919 	  usage (stdout, 0);
920 	  break;
921 
922 	case 'V':
923 	  print_version ("windres");
924 	  break;
925 
926 	default:
927 	  usage (stderr, 1);
928 	  break;
929 	}
930     }
931 
932   if (input_filename == NULL && optind < argc)
933     {
934       input_filename = argv[optind];
935       ++optind;
936     }
937 
938   if (output_filename == NULL && optind < argc)
939     {
940       output_filename = argv[optind];
941       ++optind;
942     }
943 
944   if (argc != optind)
945     usage (stderr, 1);
946 
947   if (input_format == RES_FORMAT_UNKNOWN)
948     {
949       if (input_filename == NULL)
950 	input_format = RES_FORMAT_RC;
951       else
952 	input_format = format_from_filename (input_filename, 1);
953     }
954 
955   if (output_format == RES_FORMAT_UNKNOWN)
956     {
957       if (output_filename == NULL)
958 	output_format = RES_FORMAT_RC;
959       else
960 	output_format = format_from_filename (output_filename, 0);
961     }
962 
963   /* Read the input file.  */
964   switch (input_format)
965     {
966     default:
967       abort ();
968     case RES_FORMAT_RC:
969       resources = read_rc_file (input_filename, preprocessor, preprocargs,
970 				language, use_temp_file);
971       break;
972     case RES_FORMAT_RES:
973       resources = read_res_file (input_filename);
974       break;
975     case RES_FORMAT_COFF:
976       resources = read_coff_rsrc (input_filename, target);
977       break;
978     }
979 
980   if (resources == NULL)
981     fatal (_("no resources"));
982 
983   /* Sort the resources.  This is required for COFF, convenient for
984      rc, and unimportant for res.  */
985   resources = sort_resources (resources);
986 
987   /* Write the output file.  */
988   reswr_init ();
989 
990   switch (output_format)
991     {
992     default:
993       abort ();
994     case RES_FORMAT_RC:
995       write_rc_file (output_filename, resources);
996       break;
997     case RES_FORMAT_RES:
998       write_res_file (output_filename, resources);
999       break;
1000     case RES_FORMAT_COFF:
1001       write_coff_file (output_filename, target, resources);
1002       break;
1003     }
1004 
1005   xexit (0);
1006   return 0;
1007 }
1008