* Many files: Added gettext invocations around user-visible
[external/binutils.git] / binutils / windres.c
1 /* windres.c -- a program to manipulate Windows resources
2    Copyright 1997, 1998 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 /* Unicode support.  */
235
236 /* Convert an ASCII string to a unicode string.  We just copy it,
237    expanding chars to shorts, rather than doing something intelligent.  */
238
239 void
240 unicode_from_ascii (length, unicode, ascii)
241      int *length;
242      unichar **unicode;
243      const char *ascii;
244 {
245   int len;
246   const char *s;
247   unsigned short *w;
248
249   len = strlen (ascii);
250
251   if (length != NULL)
252     *length = len;
253
254   *unicode = ((unichar *) res_alloc ((len + 1) * sizeof (unichar)));
255
256   for (s = ascii, w = *unicode; *s != '\0'; s++, w++)
257     *w = *s & 0xff;
258   *w = 0;
259 }
260
261 /* Print the unicode string UNICODE to the file E.  LENGTH is the
262    number of characters to print, or -1 if we should print until the
263    end of the string.  */
264
265 void
266 unicode_print (e, unicode, length)
267      FILE *e;
268      const unichar *unicode;
269      int length;
270 {
271   while (1)
272     {
273       unichar ch;
274
275       if (length == 0)
276         return;
277       if (length > 0)
278         --length;
279
280       ch = *unicode;
281
282       if (ch == 0 && length < 0)
283         return;
284
285       ++unicode;
286
287       if ((ch & 0x7f) == ch)
288         {
289           if (ch == '\\')
290             fputs ("\\", e);
291           else if (isprint (ch))
292             putc (ch, e);
293           else
294             {
295               switch (ch)
296                 {
297                 case ESCAPE_A:
298                   fputs ("\\a", e);
299                   break;
300
301                 case ESCAPE_B:
302                   fputs ("\\b", e);
303                   break;
304
305                 case ESCAPE_F:
306                   fputs ("\\f", e);
307                   break;
308
309                 case ESCAPE_N:
310                   fputs ("\\n", e);
311                   break;
312
313                 case ESCAPE_R:
314                   fputs ("\\r", e);
315                   break;
316
317                 case ESCAPE_T:
318                   fputs ("\\t", e);
319                   break;
320
321                 case ESCAPE_V:
322                   fputs ("\\v", e);
323                   break;
324
325                 default:
326                   fprintf (e, "\\%03o", (unsigned int) ch);
327                   break;
328                 }
329             }
330         }
331       else if ((ch & 0xff) == ch)
332         fprintf (e, "\\%03o", (unsigned int) ch);
333       else
334         fprintf (e, "\\x%x", (unsigned int) ch);
335     }
336 }
337 \f
338 /* Compare two resource ID's.  We consider name entries to come before
339    numeric entries, because that is how they appear in the COFF .rsrc
340    section.  */
341
342 int
343 res_id_cmp (a, b)
344      struct res_id a;
345      struct res_id b;
346 {
347   if (! a.named)
348     {
349       if (b.named)
350         return 1;
351       if (a.u.id > b.u.id)
352         return 1;
353       else if (a.u.id < b.u.id)
354         return -1;
355       else
356         return 0;
357     }
358   else
359     {
360       unichar *as, *ase, *bs, *bse;
361
362       if (! b.named)
363         return -1;
364
365       as = a.u.n.name;
366       ase = as + a.u.n.length;
367       bs = b.u.n.name;
368       bse = bs + b.u.n.length;
369
370       while (as < ase)
371         {
372           int i;
373
374           if (bs >= bse)
375             return 1;
376           i = (int) *as - (int) *bs;
377           if (i != 0)
378             return i;
379           ++as;
380           ++bs;
381         }
382
383       if (bs < bse)
384         return -1;
385
386       return 0;
387     }
388 }
389
390 /* Print a resource ID.  */
391
392 void
393 res_id_print (stream, id, quote)
394      FILE *stream;
395      struct res_id id;
396      int quote;
397 {
398   if (! id.named)
399     fprintf (stream, "%lu", id.u.id);
400   else
401     {
402       if (quote)
403         putc ('"', stream);
404       unicode_print (stream, id.u.n.name, id.u.n.length);
405       if (quote)
406         putc ('"', stream);
407     }
408 }
409
410 /* Print a list of resource ID's.  */
411
412 void
413 res_ids_print (stream, cids, ids)
414      FILE *stream;
415      int cids;
416      const struct res_id *ids;
417 {
418   int i;
419
420   for (i = 0; i < cids; i++)
421     {
422       res_id_print (stream, ids[i], 1);
423       if (i + 1 < cids)
424         fprintf (stream, ": ");
425     }
426 }
427
428 /* Convert an ASCII string to a resource ID.  */
429
430 void
431 res_string_to_id (res_id, string)
432      struct res_id *res_id;
433      const char *string;
434 {
435   res_id->named = 1;
436   unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
437 }
438
439 /* Define a resource.  The arguments are the resource tree, RESOURCES,
440    and the location at which to put it in the tree, CIDS and IDS.
441    This returns a newly allocated res_resource structure, which the
442    caller is expected to initialize.  If DUPOK is non-zero, then if a
443    resource with this ID exists, it is returned.  Otherwise, a warning
444    is issued, and a new resource is created replacing the existing
445    one.  */
446
447 struct res_resource *
448 define_resource (resources, cids, ids, dupok)
449      struct res_directory **resources;
450      int cids;
451      const struct res_id *ids;
452      int dupok;
453 {
454   struct res_entry *re = NULL;
455   int i;
456
457   assert (cids > 0);
458   for (i = 0; i < cids; i++)
459     {
460       struct res_entry **pp;
461
462       if (*resources == NULL)
463         {
464           static unsigned long timeval;
465
466           /* Use the same timestamp for every resource created in a
467              single run.  */
468           if (timeval == 0)
469             timeval = time (NULL);
470
471           *resources = ((struct res_directory *)
472                         res_alloc (sizeof **resources));
473           (*resources)->characteristics = 0;
474           (*resources)->time = timeval;
475           (*resources)->major = 0;
476           (*resources)->minor = 0;
477           (*resources)->entries = NULL;
478         }
479
480       for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
481         if (res_id_cmp ((*pp)->id, ids[i]) == 0)
482           break;
483
484       if (*pp != NULL)
485         re = *pp;
486       else
487         {
488           re = (struct res_entry *) res_alloc (sizeof *re);
489           re->next = NULL;
490           re->id = ids[i];
491           if ((i + 1) < cids)
492             {
493               re->subdir = 1;
494               re->u.dir = NULL;
495             }
496           else
497             {
498               re->subdir = 0;
499               re->u.res = NULL;
500             }
501
502           *pp = re;
503         }
504
505       if ((i + 1) < cids)
506         {
507           if (! re->subdir)
508             {
509               fprintf (stderr, "%s: ", program_name);
510               res_ids_print (stderr, i, ids);
511               fprintf (stderr, _(": expected to be a directory\n"));
512               xexit (1);
513             }
514
515           resources = &re->u.dir;
516         }
517     }
518
519   if (re->subdir)
520     {
521       fprintf (stderr, "%s: ", program_name);
522       res_ids_print (stderr, cids, ids);
523       fprintf (stderr, _(": expected to be a leaf\n"));
524       xexit (1);
525     }
526
527   if (re->u.res != NULL)
528     {
529       if (dupok)
530         return re->u.res;
531
532       fprintf (stderr, _("%s: warning: "), program_name);
533       res_ids_print (stderr, cids, ids);
534       fprintf (stderr, _(": duplicate value\n"));
535     }
536
537   re->u.res = ((struct res_resource *)
538                res_alloc (sizeof (struct res_resource)));
539
540   re->u.res->type = RES_TYPE_UNINITIALIZED;
541   memset (&re->u.res->res_info, 0, sizeof (struct res_res_info));
542   memset (&re->u.res->coff_info, 0, sizeof (struct res_coff_info));
543
544   return re->u.res;
545 }
546
547 /* Define a standard resource.  This is a version of define_resource
548    that just takes type, name, and language arguments.  */
549
550 struct res_resource *
551 define_standard_resource (resources, type, name, language, dupok)
552      struct res_directory **resources;
553      int type;
554      struct res_id name;
555      int language;
556      int dupok;
557 {
558   struct res_id a[3];
559
560   a[0].named = 0;
561   a[0].u.id = type;
562   a[1] = name;
563   a[2].named = 0;
564   a[2].u.id = language;
565   return define_resource (resources, 3, a, dupok);
566 }
567
568 /* Comparison routine for resource sorting.  */
569
570 static int
571 cmp_res_entry (p1, p2)
572      const PTR p1;
573      const PTR p2;
574 {
575   const struct res_entry **re1, **re2;
576
577   re1 = (const struct res_entry **) p1;
578   re2 = (const struct res_entry **) p2;
579   return res_id_cmp ((*re1)->id, (*re2)->id);
580 }
581
582 /* Sort the resources.  */
583
584 static struct res_directory *
585 sort_resources (resdir)
586      struct res_directory *resdir;
587 {
588   int c, i;
589   struct res_entry *re;
590   struct res_entry **a;
591
592   if (resdir->entries == NULL)
593     return resdir;
594
595   c = 0;
596   for (re = resdir->entries; re != NULL; re = re->next)
597     ++c;
598
599   /* This is a recursive routine, so using xmalloc is probably better
600      than alloca.  */
601   a = (struct res_entry **) xmalloc (c * sizeof (struct res_entry *));
602
603   for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
604     a[i] = re;
605
606   qsort (a, c, sizeof (struct res_entry *), cmp_res_entry);
607
608   resdir->entries = a[0];
609   for (i = 0; i < c - 1; i++)
610     a[i]->next = a[i + 1];
611   a[i]->next = NULL;
612
613   free (a);
614
615   /* Now sort the subdirectories.  */
616
617   for (re = resdir->entries; re != NULL; re = re->next)
618     if (re->subdir)
619       re->u.dir = sort_resources (re->u.dir);
620
621   return resdir;
622 }
623 \f
624 /* Return whether the dialog resource DIALOG is a DIALOG or a
625    DIALOGEX.  */
626
627 int
628 extended_dialog (dialog)
629      const struct dialog *dialog;
630 {
631   const struct dialog_control *c;
632
633   if (dialog->ex != NULL)
634     return 1;
635
636   for (c = dialog->controls; c != NULL; c = c->next)
637     if (c->data != NULL || c->help != 0)
638       return 1;
639
640   return 0;
641 }
642
643 /* Return whether MENUITEMS are a MENU or a MENUEX.  */
644
645 int
646 extended_menu (menu)
647      const struct menu *menu;
648 {
649   return extended_menuitems (menu->items);
650 }
651
652 static int
653 extended_menuitems (menuitems)
654      const struct menuitem *menuitems;
655 {
656   const struct menuitem *mi;
657
658   for (mi = menuitems; mi != NULL; mi = mi->next)
659     {
660       if (mi->help != 0 || mi->state != 0)
661         return 1;
662       if (mi->popup != NULL && mi->id != 0)
663         return 1;
664       if ((mi->type
665            & ~ (MENUITEM_CHECKED
666                 | MENUITEM_GRAYED
667                 | MENUITEM_HELP
668                 | MENUITEM_INACTIVE
669                 | MENUITEM_MENUBARBREAK
670                 | MENUITEM_MENUBREAK))
671           != 0)
672         return 1;
673       if (mi->popup != NULL)
674         {
675           if (extended_menuitems (mi->popup))
676             return 1;
677         }
678     }
679
680   return 0;
681 }
682 \f
683 /* Convert a string to a format type, or exit if it can't be done.  */
684
685 static enum res_format
686 format_from_name (name)
687      const char *name;
688 {
689   const struct format_map *m;
690
691   for (m = format_names; m->name != NULL; m++)
692     if (strcasecmp (m->name, name) == 0)
693       break;
694
695   if (m->name == NULL)
696     {
697       fprintf (stderr, _("%s: unknown format type `%s'\n"), program_name, name);
698       fprintf (stderr, _("%s: supported formats:"), program_name);
699       for (m = format_names; m->name != NULL; m++)
700         fprintf (stderr, " %s", m->name);
701       fprintf (stderr, "\n");
702       xexit (1);
703     }
704
705   return m->format;
706 }
707
708 /* Work out a format type given a file name.  If INPUT is non-zero,
709    it's OK to look at the file itself.  */
710
711 static enum res_format
712 format_from_filename (filename, input)
713      const char *filename;
714      int input;
715 {
716   const char *ext;
717   FILE *e;
718   unsigned char b1, b2, b3, b4, b5;
719   int magic;
720
721   /* If we have an extension, see if we recognize it as implying a
722      particular format.  */
723   ext = strrchr (filename, '.');
724   if (ext != NULL)
725     {
726       const struct format_map *m;
727
728       ++ext;
729       for (m = format_fileexts; m->name != NULL; m++)
730         if (strcasecmp (m->name, ext) == 0)
731           return m->format;
732     }
733
734   /* If we don't recognize the name of an output file, assume it's a
735      COFF file.  */
736
737   if (! input)
738     return RES_FORMAT_COFF;
739
740   /* Read the first few bytes of the file to see if we can guess what
741      it is.  */
742
743   e = fopen (filename, FOPEN_RB);
744   if (e == NULL)
745     fatal ("%s: %s", filename, strerror (errno));
746
747   b1 = getc (e);
748   b2 = getc (e);
749   b3 = getc (e);
750   b4 = getc (e);
751   b5 = getc (e);
752
753   fclose (e);
754
755   /* A PE executable starts with 0x4d 0x5a.  */
756   if (b1 == 0x4d && b2 == 0x5a)
757     return RES_FORMAT_COFF;
758
759   /* A COFF .o file starts with a COFF magic number.  */
760   magic = (b2 << 8) | b1;
761   switch (magic)
762     {
763     case 0x14c: /* i386 */
764     case 0x166: /* MIPS */
765     case 0x184: /* Alpha */
766     case 0x268: /* 68k */
767     case 0x1f0: /* PowerPC */
768     case 0x290: /* PA */
769       return RES_FORMAT_COFF;
770     }
771
772   /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0.  */
773   if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
774     return RES_FORMAT_RES;
775
776   /* If every character is printable or space, assume it's an RC file.  */
777   if ((isprint (b1) || isspace (b1))
778       && (isprint (b2) || isspace (b2))
779       && (isprint (b3) || isspace (b3))
780       && (isprint (b4) || isspace (b4))
781       && (isprint (b5) || isspace (b5)))
782     return RES_FORMAT_RC;
783
784   /* Otherwise, we give up.  */
785   fatal (_("can not determine type of file `%s'; use the -I option"),
786          filename);
787
788   /* Return something to silence the compiler warning.  */
789   return RES_FORMAT_UNKNOWN;
790 }
791
792 /* Print a usage message and exit.  */
793
794 static void
795 usage (stream, status)
796      FILE *stream;
797      int status;
798 {
799   fprintf (stream, _("Usage: %s [options] [input-file] [output-file]\n"),
800            program_name);
801   fprintf (stream, _("\
802 Options:\n\
803   -i FILE, --input FILE       Name input file\n\
804   -o FILE, --output FILE      Name output file\n\
805   -I FORMAT, --input-format FORMAT\n\
806                               Specify input format\n\
807   -O FORMAT, --output-format FORMAT\n\
808                               Specify output format\n\
809   -F TARGET, --target TARGET  Specify COFF target\n\
810   --preprocessor PROGRAM      Program to use to preprocess rc file\n\
811   --include-dir DIR           Include directory when preprocessing rc file\n\
812   --define SYM[=VAL]          Define SYM when preprocessing rc file\n\
813   --language VAL              Set language when reading rc file\n"));
814 #ifdef YYDEBUG
815   fprintf (stream, _("\
816   --yydebug                   Turn on parser debugging\n"));
817 #endif
818   fprintf (stream, _("\
819   --help                      Print this help message\n\
820   --version                   Print version information\n"));
821   fprintf (stream, _("\
822 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
823 extension if not specified.  A single file name is an input file.\n\
824 No input-file is stdin, default rc.  No output-file is stdout, default rc.\n"));
825   list_supported_targets (program_name, stream);
826   if (status == 0)
827     fprintf (stream, _("Report bugs to bug-gnu-utils@gnu.org\n"));
828   exit (status);
829 }
830
831 /* The main function.  */
832
833 int
834 main (argc, argv)
835      int argc;
836      char **argv;
837 {
838   int c;
839   char *input_filename;
840   char *output_filename;
841   enum res_format input_format;
842   enum res_format output_format;
843   char *target;
844   char *preprocessor;
845   char *preprocargs;
846   int language;
847   struct res_directory *resources;
848
849   program_name = argv[0];
850   xmalloc_set_program_name (program_name);
851
852   bfd_init ();
853   set_default_bfd_target ();
854
855   res_init ();
856
857   input_filename = NULL;
858   output_filename = NULL;
859   input_format = RES_FORMAT_UNKNOWN;
860   output_format = RES_FORMAT_UNKNOWN;
861   target = NULL;
862   preprocessor = NULL;
863   preprocargs = NULL;
864   language = -1;
865
866   while ((c = getopt_long (argc, argv, "i:o:I:O:F:", long_options,
867                            (int *) 0)) != EOF)
868     {
869       switch (c)
870         {
871         case 'i':
872           input_filename = optarg;
873           break;
874
875         case 'o':
876           output_filename = optarg;
877           break;
878
879         case 'I':
880           input_format = format_from_name (optarg);
881           break;
882
883         case 'O':
884           output_format = format_from_name (optarg);
885           break;
886
887         case 'F':
888           target = optarg;
889           break;
890
891         case OPTION_PREPROCESSOR:
892           preprocessor = optarg;
893           break;
894
895         case OPTION_DEFINE:
896           if (preprocargs == NULL)
897             {
898               preprocargs = xmalloc (strlen (optarg) + 3);
899               sprintf (preprocargs, "-D%s", optarg);
900             }
901           else
902             {
903               char *n;
904
905               n = xmalloc (strlen (preprocargs) + strlen (optarg) + 4);
906               sprintf (n, "%s -D%s", preprocargs, optarg);
907               free (preprocargs);
908               preprocargs = n;
909             }
910           break;
911
912         case OPTION_INCLUDE_DIR:
913           if (preprocargs == NULL)
914             {
915               preprocargs = xmalloc (strlen (optarg) + 3);
916               sprintf (preprocargs, "-I%s", optarg);
917             }
918           else
919             {
920               char *n;
921
922               n = xmalloc (strlen (preprocargs) + strlen (optarg) + 4);
923               sprintf (n, "%s -I%s", preprocargs, optarg);
924               free (preprocargs);
925               preprocargs = n;
926             }
927
928           {
929             struct include_dir *n, **pp;
930
931             n = (struct include_dir *) xmalloc (sizeof *n);
932             n->next = NULL;
933             n->dir = optarg;
934
935             for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
936               ;
937             *pp = n;
938           }
939
940           break;
941
942         case OPTION_LANGUAGE:
943           language = strtol (optarg, (char **) NULL, 16);
944           break;
945
946 #ifdef YYDEBUG
947         case OPTION_YYDEBUG:
948           yydebug = 1;
949           break;
950 #endif
951
952         case OPTION_HELP:
953           usage (stdout, 0);
954           break;
955
956         case OPTION_VERSION:
957           print_version ("windres");
958           break;
959
960         default:
961           usage (stderr, 1);
962           break;
963         }
964     }
965
966   if (input_filename == NULL && optind < argc)
967     {
968       input_filename = argv[optind];
969       ++optind;
970     }
971
972   if (output_filename == NULL && optind < argc)
973     {
974       output_filename = argv[optind];
975       ++optind;
976     }
977
978   if (argc != optind)
979     usage (stderr, 1);
980
981   if (input_format == RES_FORMAT_UNKNOWN)
982     {
983       if (input_filename == NULL)
984         input_format = RES_FORMAT_RC;
985       else
986         input_format = format_from_filename (input_filename, 1);
987     }
988
989   if (output_format == RES_FORMAT_UNKNOWN)
990     {
991       if (output_filename == NULL)
992         output_format = RES_FORMAT_RC;
993       else
994         output_format = format_from_filename (output_filename, 0);
995     }
996
997   /* Read the input file.  */
998
999   switch (input_format)
1000     {
1001     default:
1002       abort ();
1003     case RES_FORMAT_RC:
1004       resources = read_rc_file (input_filename, preprocessor, preprocargs,
1005                                 language);
1006       break;
1007     case RES_FORMAT_RES:
1008       resources = read_res_file (input_filename);
1009       break;
1010     case RES_FORMAT_COFF:
1011       resources = read_coff_rsrc (input_filename, target);
1012       break;
1013     }
1014
1015   if (resources == NULL)
1016     fatal (_("no resources"));
1017
1018   /* Sort the resources.  This is required for COFF, convenient for
1019      rc, and unimportant for res.  */
1020
1021   resources = sort_resources (resources);
1022
1023   /* Write the output file.  */
1024
1025   reswr_init ();
1026
1027   switch (output_format)
1028     {
1029     default:
1030       abort ();
1031     case RES_FORMAT_RC:
1032       write_rc_file (output_filename, resources);
1033       break;
1034     case RES_FORMAT_RES:
1035       write_res_file (output_filename, resources);
1036       break;
1037     case RES_FORMAT_COFF:
1038       write_coff_file (output_filename, target, resources);
1039       break;
1040     }
1041
1042   xexit (0);
1043   return 0;
1044 }
1045
1046 struct res_directory *
1047 read_res_file (filename)
1048      const char *filename;
1049 {
1050   fatal (_("read_res_file unimplemented"));
1051   return NULL;
1052 }
1053
1054 void
1055 write_res_file (filename, resources)
1056      const char *filename;
1057      const struct res_directory *resources;
1058 {
1059   fatal (_("write_res_file unimplemented"));
1060 }