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