1999-05-10 DJ Delorie <dj@cygnus.com>
[platform/upstream/binutils.git] / binutils / windres.c
1 /* windres.c -- a program to manipulate Windows resources
2    Copyright 1997, 1998, 1999 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor, Cygnus Support.
4
5    This file is part of GNU Binutils.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 /* This program can read and write Windows resources in various
23    formats.  In particular, it can act like the rc resource compiler
24    program, and it can act like the cvtres res to COFF conversion
25    program.
26
27    It is based on information taken from the following sources:
28
29    * Microsoft documentation.
30
31    * The rcl program, written by Gunther Ebert
32      <gunther.ebert@ixos-leipzig.de>.
33
34    * The res2coff program, written by Pedro A. Aranda <paag@tid.es>.
35
36    */
37
38 #include "bfd.h"
39 #include "getopt.h"
40 #include "bucomm.h"
41 #include "libiberty.h"
42 #include "obstack.h"
43 #include "windres.h"
44
45 #include <assert.h>
46 #include <ctype.h>
47 #include <time.h>
48
49 /* An enumeration of format types.  */
50
51 enum res_format
52 {
53   /* Unknown format.  */
54   RES_FORMAT_UNKNOWN,
55   /* Textual RC file.  */
56   RES_FORMAT_RC,
57   /* Binary RES file.  */
58   RES_FORMAT_RES,
59   /* COFF file.  */
60   RES_FORMAT_COFF
61 };
62
63 /* A structure used to map between format types and strings.  */
64
65 struct format_map
66 {
67   const char *name;
68   enum res_format format;
69 };
70
71 /* A mapping between names and format types.  */
72
73 static const struct format_map format_names[] =
74 {
75   { "rc", RES_FORMAT_RC },
76   { "res", RES_FORMAT_RES },
77   { "coff", RES_FORMAT_COFF },
78   { NULL, RES_FORMAT_UNKNOWN }
79 };
80
81 /* A mapping from file extensions to format types.  */
82
83 static const struct format_map format_fileexts[] =
84 {
85   { "rc", RES_FORMAT_RC },
86   { "res", RES_FORMAT_RES },
87   { "exe", RES_FORMAT_COFF },
88   { "obj", RES_FORMAT_COFF },
89   { "o", RES_FORMAT_COFF },
90   { NULL, RES_FORMAT_UNKNOWN }
91 };
92
93 /* A list of include directories.  */
94
95 struct include_dir
96 {
97   struct include_dir *next;
98   char *dir;
99 };
100
101 static struct include_dir *include_dirs;
102
103 /* Long options.  */
104
105 /* 150 isn't special; it's just an arbitrary non-ASCII char value.  */
106
107 #define OPTION_DEFINE 150
108 #define OPTION_HELP (OPTION_DEFINE + 1)
109 #define OPTION_INCLUDE_DIR (OPTION_HELP + 1)
110 #define OPTION_LANGUAGE (OPTION_INCLUDE_DIR + 1)
111 #define OPTION_PREPROCESSOR (OPTION_LANGUAGE + 1)
112 #define OPTION_VERSION (OPTION_PREPROCESSOR + 1)
113 #define OPTION_YYDEBUG (OPTION_VERSION + 1)
114
115 static const struct option long_options[] =
116 {
117   {"define", required_argument, 0, OPTION_DEFINE},
118   {"help", no_argument, 0, OPTION_HELP},
119   {"include-dir", required_argument, 0, OPTION_INCLUDE_DIR},
120   {"input-format", required_argument, 0, 'I'},
121   {"language", required_argument, 0, OPTION_LANGUAGE},
122   {"output-format", required_argument, 0, 'O'},
123   {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
124   {"target", required_argument, 0, 'F'},
125   {"version", no_argument, 0, OPTION_VERSION},
126   {"yydebug", no_argument, 0, OPTION_YYDEBUG},
127   {0, no_argument, 0, 0}
128 };
129
130 /* Static functions.  */
131
132 static void res_init PARAMS ((void));
133 static int extended_menuitems PARAMS ((const struct menuitem *));
134 static enum res_format format_from_name PARAMS ((const char *));
135 static enum res_format format_from_filename PARAMS ((const char *, int));
136 static void usage PARAMS ((FILE *, int));
137 static int cmp_res_entry PARAMS ((const PTR, const PTR));
138 static struct res_directory *sort_resources PARAMS ((struct res_directory *));
139 \f
140 /* When we are building a resource tree, we allocate everything onto
141    an obstack, so that we can free it all at once if we want.  */
142
143 #define obstack_chunk_alloc xmalloc
144 #define obstack_chunk_free free
145
146 /* The resource building obstack.  */
147
148 static struct obstack res_obstack;
149
150 /* Initialize the resource building obstack.  */
151
152 static void
153 res_init ()
154 {
155   obstack_init (&res_obstack);
156 }
157
158 /* Allocate space on the resource building obstack.  */
159
160 PTR
161 res_alloc (bytes)
162      size_t bytes;
163 {
164   return (PTR) obstack_alloc (&res_obstack, bytes);
165 }
166
167 /* We also use an obstack to save memory used while writing out a set
168    of resources.  */
169
170 static struct obstack reswr_obstack;
171
172 /* Initialize the resource writing obstack.  */
173
174 static void
175 reswr_init ()
176 {
177   obstack_init (&reswr_obstack);
178 }
179
180 /* Allocate space on the resource writing obstack.  */
181
182 PTR
183 reswr_alloc (bytes)
184      size_t bytes;
185 {
186   return (PTR) obstack_alloc (&reswr_obstack, bytes);
187 }
188 \f
189 /* Open a file using the include directory search list.  */
190
191 FILE *
192 open_file_search (filename, mode, errmsg, real_filename)
193      const char *filename;
194      const char *mode;
195      const char *errmsg;
196      char **real_filename;
197 {
198   FILE *e;
199   struct include_dir *d;
200
201   e = fopen (filename, mode);
202   if (e != NULL)
203     {
204       *real_filename = xstrdup (filename);
205       return e;
206     }
207
208   if (errno == ENOENT)
209     {
210       for (d = include_dirs; d != NULL; d = d->next)
211         {
212           char *n;
213
214           n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
215           sprintf (n, "%s/%s", d->dir, filename);
216           e = fopen (n, mode);
217           if (e != NULL)
218             {
219               *real_filename = n;
220               return e;
221             }
222
223           if (errno != ENOENT)
224             break;
225         }
226     }
227
228   fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
229
230   /* Return a value to avoid a compiler warning.  */
231   return NULL;
232 }
233 \f
234 /* Compare two resource ID's.  We consider name entries to come before
235    numeric entries, because that is how they appear in the COFF .rsrc
236    section.  */
237
238 int
239 res_id_cmp (a, b)
240      struct res_id a;
241      struct res_id b;
242 {
243   if (! a.named)
244     {
245       if (b.named)
246         return 1;
247       if (a.u.id > b.u.id)
248         return 1;
249       else if (a.u.id < b.u.id)
250         return -1;
251       else
252         return 0;
253     }
254   else
255     {
256       unichar *as, *ase, *bs, *bse;
257
258       if (! b.named)
259         return -1;
260
261       as = a.u.n.name;
262       ase = as + a.u.n.length;
263       bs = b.u.n.name;
264       bse = bs + b.u.n.length;
265
266       while (as < ase)
267         {
268           int i;
269
270           if (bs >= bse)
271             return 1;
272           i = (int) *as - (int) *bs;
273           if (i != 0)
274             return i;
275           ++as;
276           ++bs;
277         }
278
279       if (bs < bse)
280         return -1;
281
282       return 0;
283     }
284 }
285
286 /* Print a resource ID.  */
287
288 void
289 res_id_print (stream, id, quote)
290      FILE *stream;
291      struct res_id id;
292      int quote;
293 {
294   if (! id.named)
295     fprintf (stream, "%lu", id.u.id);
296   else
297     {
298       if (quote)
299         putc ('"', stream);
300       unicode_print (stream, id.u.n.name, id.u.n.length);
301       if (quote)
302         putc ('"', stream);
303     }
304 }
305
306 /* Print a list of resource ID's.  */
307
308 void
309 res_ids_print (stream, cids, ids)
310      FILE *stream;
311      int cids;
312      const struct res_id *ids;
313 {
314   int i;
315
316   for (i = 0; i < cids; i++)
317     {
318       res_id_print (stream, ids[i], 1);
319       if (i + 1 < cids)
320         fprintf (stream, ": ");
321     }
322 }
323
324 /* Convert an ASCII string to a resource ID.  */
325
326 void
327 res_string_to_id (res_id, string)
328      struct res_id *res_id;
329      const char *string;
330 {
331   res_id->named = 1;
332   unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
333 }
334
335 /* Define a resource.  The arguments are the resource tree, RESOURCES,
336    and the location at which to put it in the tree, CIDS and IDS.
337    This returns a newly allocated res_resource structure, which the
338    caller is expected to initialize.  If DUPOK is non-zero, then if a
339    resource with this ID exists, it is returned.  Otherwise, a warning
340    is issued, and a new resource is created replacing the existing
341    one.  */
342
343 struct res_resource *
344 define_resource (resources, cids, ids, dupok)
345      struct res_directory **resources;
346      int cids;
347      const struct res_id *ids;
348      int dupok;
349 {
350   struct res_entry *re = NULL;
351   int i;
352
353   assert (cids > 0);
354   for (i = 0; i < cids; i++)
355     {
356       struct res_entry **pp;
357
358       if (*resources == NULL)
359         {
360           static unsigned long timeval;
361
362           /* Use the same timestamp for every resource created in a
363              single run.  */
364           if (timeval == 0)
365             timeval = time (NULL);
366
367           *resources = ((struct res_directory *)
368                         res_alloc (sizeof **resources));
369           (*resources)->characteristics = 0;
370           (*resources)->time = timeval;
371           (*resources)->major = 0;
372           (*resources)->minor = 0;
373           (*resources)->entries = NULL;
374         }
375
376       for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
377         if (res_id_cmp ((*pp)->id, ids[i]) == 0)
378           break;
379
380       if (*pp != NULL)
381         re = *pp;
382       else
383         {
384           re = (struct res_entry *) res_alloc (sizeof *re);
385           re->next = NULL;
386           re->id = ids[i];
387           if ((i + 1) < cids)
388             {
389               re->subdir = 1;
390               re->u.dir = NULL;
391             }
392           else
393             {
394               re->subdir = 0;
395               re->u.res = NULL;
396             }
397
398           *pp = re;
399         }
400
401       if ((i + 1) < cids)
402         {
403           if (! re->subdir)
404             {
405               fprintf (stderr, "%s: ", program_name);
406               res_ids_print (stderr, i, ids);
407               fprintf (stderr, _(": expected to be a directory\n"));
408               xexit (1);
409             }
410
411           resources = &re->u.dir;
412         }
413     }
414
415   if (re->subdir)
416     {
417       fprintf (stderr, "%s: ", program_name);
418       res_ids_print (stderr, cids, ids);
419       fprintf (stderr, _(": expected to be a leaf\n"));
420       xexit (1);
421     }
422
423   if (re->u.res != NULL)
424     {
425       if (dupok)
426         return re->u.res;
427
428       fprintf (stderr, _("%s: warning: "), program_name);
429       res_ids_print (stderr, cids, ids);
430       fprintf (stderr, _(": duplicate value\n"));
431     }
432
433   re->u.res = ((struct res_resource *)
434                res_alloc (sizeof (struct res_resource)));
435
436   re->u.res->type = RES_TYPE_UNINITIALIZED;
437   memset (&re->u.res->res_info, 0, sizeof (struct res_res_info));
438   memset (&re->u.res->coff_info, 0, sizeof (struct res_coff_info));
439
440   return re->u.res;
441 }
442
443 /* Define a standard resource.  This is a version of define_resource
444    that just takes type, name, and language arguments.  */
445
446 struct res_resource *
447 define_standard_resource (resources, type, name, language, dupok)
448      struct res_directory **resources;
449      int type;
450      struct res_id name;
451      int language;
452      int dupok;
453 {
454   struct res_id a[3];
455
456   a[0].named = 0;
457   a[0].u.id = type;
458   a[1] = name;
459   a[2].named = 0;
460   a[2].u.id = language;
461   return define_resource (resources, 3, a, dupok);
462 }
463
464 /* Comparison routine for resource sorting.  */
465
466 static int
467 cmp_res_entry (p1, p2)
468      const PTR p1;
469      const PTR p2;
470 {
471   const struct res_entry **re1, **re2;
472
473   re1 = (const struct res_entry **) p1;
474   re2 = (const struct res_entry **) p2;
475   return res_id_cmp ((*re1)->id, (*re2)->id);
476 }
477
478 /* Sort the resources.  */
479
480 static struct res_directory *
481 sort_resources (resdir)
482      struct res_directory *resdir;
483 {
484   int c, i;
485   struct res_entry *re;
486   struct res_entry **a;
487
488   if (resdir->entries == NULL)
489     return resdir;
490
491   c = 0;
492   for (re = resdir->entries; re != NULL; re = re->next)
493     ++c;
494
495   /* This is a recursive routine, so using xmalloc is probably better
496      than alloca.  */
497   a = (struct res_entry **) xmalloc (c * sizeof (struct res_entry *));
498
499   for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
500     a[i] = re;
501
502   qsort (a, c, sizeof (struct res_entry *), cmp_res_entry);
503
504   resdir->entries = a[0];
505   for (i = 0; i < c - 1; i++)
506     a[i]->next = a[i + 1];
507   a[i]->next = NULL;
508
509   free (a);
510
511   /* Now sort the subdirectories.  */
512
513   for (re = resdir->entries; re != NULL; re = re->next)
514     if (re->subdir)
515       re->u.dir = sort_resources (re->u.dir);
516
517   return resdir;
518 }
519 \f
520 /* Return whether the dialog resource DIALOG is a DIALOG or a
521    DIALOGEX.  */
522
523 int
524 extended_dialog (dialog)
525      const struct dialog *dialog;
526 {
527   const struct dialog_control *c;
528
529   if (dialog->ex != NULL)
530     return 1;
531
532   for (c = dialog->controls; c != NULL; c = c->next)
533     if (c->data != NULL || c->help != 0)
534       return 1;
535
536   return 0;
537 }
538
539 /* Return whether MENUITEMS are a MENU or a MENUEX.  */
540
541 int
542 extended_menu (menu)
543      const struct menu *menu;
544 {
545   return extended_menuitems (menu->items);
546 }
547
548 static int
549 extended_menuitems (menuitems)
550      const struct menuitem *menuitems;
551 {
552   const struct menuitem *mi;
553
554   for (mi = menuitems; mi != NULL; mi = mi->next)
555     {
556       if (mi->help != 0 || mi->state != 0)
557         return 1;
558       if (mi->popup != NULL && mi->id != 0)
559         return 1;
560       if ((mi->type
561            & ~ (MENUITEM_CHECKED
562                 | MENUITEM_GRAYED
563                 | MENUITEM_HELP
564                 | MENUITEM_INACTIVE
565                 | MENUITEM_MENUBARBREAK
566                 | MENUITEM_MENUBREAK))
567           != 0)
568         return 1;
569       if (mi->popup != NULL)
570         {
571           if (extended_menuitems (mi->popup))
572             return 1;
573         }
574     }
575
576   return 0;
577 }
578 \f
579 /* Convert a string to a format type, or exit if it can't be done.  */
580
581 static enum res_format
582 format_from_name (name)
583      const char *name;
584 {
585   const struct format_map *m;
586
587   for (m = format_names; m->name != NULL; m++)
588     if (strcasecmp (m->name, name) == 0)
589       break;
590
591   if (m->name == NULL)
592     {
593       fprintf (stderr, _("%s: unknown format type `%s'\n"), program_name, name);
594       fprintf (stderr, _("%s: supported formats:"), program_name);
595       for (m = format_names; m->name != NULL; m++)
596         fprintf (stderr, " %s", m->name);
597       fprintf (stderr, "\n");
598       xexit (1);
599     }
600
601   return m->format;
602 }
603
604 /* Work out a format type given a file name.  If INPUT is non-zero,
605    it's OK to look at the file itself.  */
606
607 static enum res_format
608 format_from_filename (filename, input)
609      const char *filename;
610      int input;
611 {
612   const char *ext;
613   FILE *e;
614   unsigned char b1, b2, b3, b4, b5;
615   int magic;
616
617   /* If we have an extension, see if we recognize it as implying a
618      particular format.  */
619   ext = strrchr (filename, '.');
620   if (ext != NULL)
621     {
622       const struct format_map *m;
623
624       ++ext;
625       for (m = format_fileexts; m->name != NULL; m++)
626         if (strcasecmp (m->name, ext) == 0)
627           return m->format;
628     }
629
630   /* If we don't recognize the name of an output file, assume it's a
631      COFF file.  */
632
633   if (! input)
634     return RES_FORMAT_COFF;
635
636   /* Read the first few bytes of the file to see if we can guess what
637      it is.  */
638
639   e = fopen (filename, FOPEN_RB);
640   if (e == NULL)
641     fatal ("%s: %s", filename, strerror (errno));
642
643   b1 = getc (e);
644   b2 = getc (e);
645   b3 = getc (e);
646   b4 = getc (e);
647   b5 = getc (e);
648
649   fclose (e);
650
651   /* A PE executable starts with 0x4d 0x5a.  */
652   if (b1 == 0x4d && b2 == 0x5a)
653     return RES_FORMAT_COFF;
654
655   /* A COFF .o file starts with a COFF magic number.  */
656   magic = (b2 << 8) | b1;
657   switch (magic)
658     {
659     case 0x14c: /* i386 */
660     case 0x166: /* MIPS */
661     case 0x184: /* Alpha */
662     case 0x268: /* 68k */
663     case 0x1f0: /* PowerPC */
664     case 0x290: /* PA */
665       return RES_FORMAT_COFF;
666     }
667
668   /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0.  */
669   if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
670     return RES_FORMAT_RES;
671
672   /* If every character is printable or space, assume it's an RC file.  */
673   if ((isprint (b1) || isspace (b1))
674       && (isprint (b2) || isspace (b2))
675       && (isprint (b3) || isspace (b3))
676       && (isprint (b4) || isspace (b4))
677       && (isprint (b5) || isspace (b5)))
678     return RES_FORMAT_RC;
679
680   /* Otherwise, we give up.  */
681   fatal (_("can not determine type of file `%s'; use the -I option"),
682          filename);
683
684   /* Return something to silence the compiler warning.  */
685   return RES_FORMAT_UNKNOWN;
686 }
687
688 /* Print a usage message and exit.  */
689
690 static void
691 usage (stream, status)
692      FILE *stream;
693      int status;
694 {
695   fprintf (stream, _("Usage: %s [options] [input-file] [output-file]\n"),
696            program_name);
697   fprintf (stream, _("\
698 Options:\n\
699   -i FILE, --input FILE       Name input file\n\
700   -o FILE, --output FILE      Name output file\n\
701   -I FORMAT, --input-format FORMAT\n\
702                               Specify input format\n\
703   -O FORMAT, --output-format FORMAT\n\
704                               Specify output format\n\
705   -F TARGET, --target TARGET  Specify COFF target\n\
706   --preprocessor PROGRAM      Program to use to preprocess rc file\n\
707   --include-dir DIR           Include directory when preprocessing rc file\n\
708   --define SYM[=VAL]          Define SYM when preprocessing rc file\n\
709   --language VAL              Set language when reading rc file\n"));
710 #ifdef YYDEBUG
711   fprintf (stream, _("\
712   --yydebug                   Turn on parser debugging\n"));
713 #endif
714   fprintf (stream, _("\
715   --help                      Print this help message\n\
716   --version                   Print version information\n"));
717   fprintf (stream, _("\
718 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
719 extension if not specified.  A single file name is an input file.\n\
720 No input-file is stdin, default rc.  No output-file is stdout, default rc.\n"));
721   list_supported_targets (program_name, stream);
722   if (status == 0)
723     fprintf (stream, _("Report bugs to bug-gnu-utils@gnu.org\n"));
724   exit (status);
725 }
726
727 /* Quote characters that will confuse the shell when we run the preprocessor */
728 static const char *quot (string)
729      const char *string;
730 {
731   static char *buf = 0;
732   static int buflen = 0;
733   int slen = strlen (string);
734   const char *src;
735   char *dest;
736
737   if ((buflen < slen * 2 + 2) || !buf)
738     {
739       buflen = slen * 2 + 2;
740       if (buf)
741         free (buf);
742       buf = (char *) xmalloc (buflen);
743     }
744
745   for (src=string, dest=buf; *src; src++, dest++)
746     {
747       if (*src == '(' || *src == ')' || *src == ' ')
748         *dest++ = '\\';
749       *dest = *src;
750     }
751   *dest = 0;
752   return buf;
753 }
754
755 /* The main function.  */
756
757 int
758 main (argc, argv)
759      int argc;
760      char **argv;
761 {
762   int c;
763   char *input_filename;
764   char *output_filename;
765   enum res_format input_format;
766   enum res_format output_format;
767   char *target;
768   char *preprocessor;
769   char *preprocargs;
770   const char *quotedarg;
771   int language;
772   struct res_directory *resources;
773
774 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
775   setlocale (LC_MESSAGES, "");
776 #endif
777   bindtextdomain (PACKAGE, LOCALEDIR);
778   textdomain (PACKAGE);
779
780   program_name = argv[0];
781   xmalloc_set_program_name (program_name);
782
783   bfd_init ();
784   set_default_bfd_target ();
785
786   res_init ();
787
788   input_filename = NULL;
789   output_filename = NULL;
790   input_format = RES_FORMAT_UNKNOWN;
791   output_format = RES_FORMAT_UNKNOWN;
792   target = NULL;
793   preprocessor = NULL;
794   preprocargs = NULL;
795   language = -1;
796
797   while ((c = getopt_long (argc, argv, "i:o:I:O:F:D:", long_options,
798                            (int *) 0)) != EOF)
799     {
800       switch (c)
801         {
802         case 'i':
803           input_filename = optarg;
804           break;
805
806         case 'o':
807           output_filename = optarg;
808           break;
809
810         case 'I':
811           input_format = format_from_name (optarg);
812           break;
813
814         case 'O':
815           output_format = format_from_name (optarg);
816           break;
817
818         case 'F':
819           target = optarg;
820           break;
821
822         case OPTION_PREPROCESSOR:
823           preprocessor = optarg;
824           break;
825
826         case 'D':
827         case OPTION_DEFINE:
828           if (preprocargs == NULL)
829             {
830               quotedarg = quot (optarg);
831               preprocargs = xmalloc (strlen (quotedarg) + 3);
832               sprintf (preprocargs, "-D%s", quotedarg);
833             }
834           else
835             {
836               char *n;
837
838               quotedarg = quot (optarg);
839               n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
840               sprintf (n, "%s -D%s", preprocargs, quotedarg);
841               free (preprocargs);
842               preprocargs = n;
843             }
844           break;
845
846         case OPTION_INCLUDE_DIR:
847           if (preprocargs == NULL)
848             {
849               quotedarg = quot (optarg);
850               preprocargs = xmalloc (strlen (quotedarg) + 3);
851               sprintf (preprocargs, "-I%s", quotedarg);
852             }
853           else
854             {
855               char *n;
856
857               quotedarg = quot (optarg);
858               n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
859               sprintf (n, "%s -I%s", preprocargs, quotedarg);
860               free (preprocargs);
861               preprocargs = n;
862             }
863
864           {
865             struct include_dir *n, **pp;
866
867             n = (struct include_dir *) xmalloc (sizeof *n);
868             n->next = NULL;
869             n->dir = optarg;
870
871             for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
872               ;
873             *pp = n;
874           }
875
876           break;
877
878         case OPTION_LANGUAGE:
879           language = strtol (optarg, (char **) NULL, 16);
880           break;
881
882 #ifdef YYDEBUG
883         case OPTION_YYDEBUG:
884           yydebug = 1;
885           break;
886 #endif
887
888         case OPTION_HELP:
889           usage (stdout, 0);
890           break;
891
892         case OPTION_VERSION:
893           print_version ("windres");
894           break;
895
896         default:
897           usage (stderr, 1);
898           break;
899         }
900     }
901
902   if (input_filename == NULL && optind < argc)
903     {
904       input_filename = argv[optind];
905       ++optind;
906     }
907
908   if (output_filename == NULL && optind < argc)
909     {
910       output_filename = argv[optind];
911       ++optind;
912     }
913
914   if (argc != optind)
915     usage (stderr, 1);
916
917   if (input_format == RES_FORMAT_UNKNOWN)
918     {
919       if (input_filename == NULL)
920         input_format = RES_FORMAT_RC;
921       else
922         input_format = format_from_filename (input_filename, 1);
923     }
924
925   if (output_format == RES_FORMAT_UNKNOWN)
926     {
927       if (output_filename == NULL)
928         output_format = RES_FORMAT_RC;
929       else
930         output_format = format_from_filename (output_filename, 0);
931     }
932
933   /* Read the input file.  */
934
935   switch (input_format)
936     {
937     default:
938       abort ();
939     case RES_FORMAT_RC:
940       resources = read_rc_file (input_filename, preprocessor, preprocargs,
941                                 language);
942       break;
943     case RES_FORMAT_RES:
944       resources = read_res_file (input_filename);
945       break;
946     case RES_FORMAT_COFF:
947       resources = read_coff_rsrc (input_filename, target);
948       break;
949     }
950
951   if (resources == NULL)
952     fatal (_("no resources"));
953
954   /* Sort the resources.  This is required for COFF, convenient for
955      rc, and unimportant for res.  */
956
957   resources = sort_resources (resources);
958
959   /* Write the output file.  */
960
961   reswr_init ();
962
963   switch (output_format)
964     {
965     default:
966       abort ();
967     case RES_FORMAT_RC:
968       write_rc_file (output_filename, resources);
969       break;
970     case RES_FORMAT_RES:
971       write_res_file (output_filename, resources);
972       break;
973     case RES_FORMAT_COFF:
974       write_coff_file (output_filename, target, resources);
975       break;
976     }
977
978   xexit (0);
979   return 0;
980 }
981