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