This commit was generated by cvs2svn to track changes on a CVS vendor
[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   fprintf (stream, "\
766   --yydebug                   Turn on parser debugging\n");
767 #endif
768   fprintf (stream, "\
769   --help                      Print this help message\n\
770   --version                   Print version information\n");
771   fprintf (stream, "\
772 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
773 extension if not specified.  A single file name is an input file.\n\
774 No input-file is stdin, default rc.  No output-file is stdout, default rc.\n");
775   list_supported_targets (program_name, stream);
776   if (status == 0)
777     fprintf (stream, "Report bugs to bug-gnu-utils@prep.ai.mit.edu\n");
778   exit (status);
779 }
780
781 /* The main function.  */
782
783 int
784 main (argc, argv)
785      int argc;
786      char **argv;
787 {
788   int c;
789   char *input_filename;
790   char *output_filename;
791   enum res_format input_format;
792   enum res_format output_format;
793   char *target;
794   char *preprocessor;
795   char *preprocargs;
796   int language;
797   struct res_directory *resources;
798
799   program_name = argv[0];
800   xmalloc_set_program_name (program_name);
801
802   bfd_init ();
803   set_default_bfd_target ();
804
805   res_init ();
806
807   input_filename = NULL;
808   output_filename = NULL;
809   input_format = RES_FORMAT_UNKNOWN;
810   output_format = RES_FORMAT_UNKNOWN;
811   target = NULL;
812   preprocessor = NULL;
813   preprocargs = NULL;
814   language = -1;
815
816   while ((c = getopt_long (argc, argv, "i:o:I:O:F:", long_options,
817                            (int *) 0)) != EOF)
818     {
819       switch (c)
820         {
821         case 'i':
822           input_filename = optarg;
823           break;
824
825         case 'o':
826           output_filename = optarg;
827           break;
828
829         case 'I':
830           input_format = format_from_name (optarg);
831           break;
832
833         case 'O':
834           output_format = format_from_name (optarg);
835           break;
836
837         case 'F':
838           target = optarg;
839           break;
840
841         case OPTION_PREPROCESSOR:
842           preprocessor = optarg;
843           break;
844
845         case OPTION_DEFINE:
846           if (preprocargs == NULL)
847             {
848               preprocargs = xmalloc (strlen (optarg) + 3);
849               sprintf (preprocargs, "-D%s", optarg);
850             }
851           else
852             {
853               char *n;
854
855               n = xmalloc (strlen (preprocargs) + strlen (optarg) + 4);
856               sprintf (n, "%s -D%s", preprocargs, optarg);
857               free (preprocargs);
858               preprocargs = n;
859             }
860           break;
861
862         case OPTION_INCLUDE_DIR:
863           if (preprocargs == NULL)
864             {
865               preprocargs = xmalloc (strlen (optarg) + 3);
866               sprintf (preprocargs, "-I%s", optarg);
867             }
868           else
869             {
870               char *n;
871
872               n = xmalloc (strlen (preprocargs) + strlen (optarg) + 4);
873               sprintf (n, "%s -I%s", preprocargs, optarg);
874               free (preprocargs);
875               preprocargs = n;
876             }
877
878           {
879             struct include_dir *n, **pp;
880
881             n = (struct include_dir *) xmalloc (sizeof *n);
882             n->next = NULL;
883             n->dir = optarg;
884
885             for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
886               ;
887             *pp = n;
888           }
889
890           break;
891
892         case OPTION_LANGUAGE:
893           language = strtol (optarg, (char **) NULL, 16);
894           break;
895
896 #ifdef YYDEBUG
897         case OPTION_YYDEBUG:
898           yydebug = 1;
899           break;
900 #endif
901
902         case OPTION_HELP:
903           usage (stdout, 0);
904           break;
905
906         case OPTION_VERSION:
907           print_version ("windres");
908           break;
909
910         default:
911           usage (stderr, 1);
912           break;
913         }
914     }
915
916   if (input_filename == NULL && optind < argc)
917     {
918       input_filename = argv[optind];
919       ++optind;
920     }
921
922   if (output_filename == NULL && optind < argc)
923     {
924       output_filename = argv[optind];
925       ++optind;
926     }
927
928   if (argc != optind)
929     usage (stderr, 1);
930
931   if (input_format == RES_FORMAT_UNKNOWN)
932     {
933       if (input_filename == NULL)
934         input_format = RES_FORMAT_RC;
935       else
936         input_format = format_from_filename (input_filename, 1);
937     }
938
939   if (output_format == RES_FORMAT_UNKNOWN)
940     {
941       if (output_filename == NULL)
942         output_format = RES_FORMAT_RC;
943       else
944         output_format = format_from_filename (output_filename, 0);
945     }
946
947   /* Read the input file.  */
948
949   switch (input_format)
950     {
951     default:
952       abort ();
953     case RES_FORMAT_RC:
954       resources = read_rc_file (input_filename, preprocessor, preprocargs,
955                                 language);
956       break;
957     case RES_FORMAT_RES:
958       resources = read_res_file (input_filename);
959       break;
960     case RES_FORMAT_COFF:
961       resources = read_coff_rsrc (input_filename, target);
962       break;
963     }
964
965   if (resources == NULL)
966     fatal ("no resources");
967
968   /* Sort the resources.  This is required for COFF, convenient for
969      rc, and unimportant for res.  */
970
971   resources = sort_resources (resources);
972
973   /* Write the output file.  */
974
975   reswr_init ();
976
977   switch (output_format)
978     {
979     default:
980       abort ();
981     case RES_FORMAT_RC:
982       write_rc_file (output_filename, resources);
983       break;
984     case RES_FORMAT_RES:
985       write_res_file (output_filename, resources);
986       break;
987     case RES_FORMAT_COFF:
988       write_coff_file (output_filename, target, resources);
989       break;
990     }
991
992   xexit (0);
993   return 0;
994 }
995
996 struct res_directory *
997 read_res_file (filename)
998      const char *filename;
999 {
1000   fatal ("read_res_file unimplemented");
1001   return NULL;
1002 }
1003
1004 void
1005 write_res_file (filename, resources)
1006      const char *filename;
1007      const struct res_directory *resources;
1008 {
1009   fatal ("write_res_file unimplemented");
1010 }