source: trunk/src/binutils/binutils/windres.c@ 610

Last change on this file since 610 was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

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