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