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