* scripttempl/elf.sc (CTOR): Handle crtbeginS.o, crtendS.o and
[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_INCLUDE_DIR 150
110 #define OPTION_PREPROCESSOR (OPTION_INCLUDE_DIR + 1)
111 #define OPTION_USE_TEMP_FILE (OPTION_PREPROCESSOR + 1)
112 #define OPTION_NO_USE_TEMP_FILE (OPTION_USE_TEMP_FILE + 1)
113 #define OPTION_YYDEBUG (OPTION_NO_USE_TEMP_FILE + 1)
114
115 static const struct option long_options[] =
116 {
117 {"define", required_argument, 0, 'D'},
118 {"help", no_argument, 0, 'h'},
119 {"include-dir", required_argument, 0, OPTION_INCLUDE_DIR},
120 {"input-format", required_argument, 0, 'I'},
121 {"language", required_argument, 0, 'l'},
122 {"output-format", required_argument, 0, 'O'},
123 {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
124 {"target", required_argument, 0, 'F'},
125 {"undefine", required_argument, 0, 'U'},
126 {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
127 {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
128 {"verbose", no_argument, 0, 'v'},
129 {"version", no_argument, 0, 'V'},
130 {"yydebug", no_argument, 0, OPTION_YYDEBUG},
131 {0, no_argument, 0, 0}
132 };
133
134 /* Static functions. */
135
136 static void res_init PARAMS ((void));
137 static int extended_menuitems PARAMS ((const struct menuitem *));
138 static enum res_format format_from_name PARAMS ((const char *));
139 static enum res_format format_from_filename PARAMS ((const char *, int));
140 static void usage PARAMS ((FILE *, int));
141 static int cmp_res_entry PARAMS ((const PTR, const PTR));
142 static struct res_directory *sort_resources PARAMS ((struct res_directory *));
143 static void reswr_init PARAMS ((void));
144 static const char * quot PARAMS ((const char *));
145 \f
146 /* When we are building a resource tree, we allocate everything onto
147 an obstack, so that we can free it all at once if we want. */
148
149 #define obstack_chunk_alloc xmalloc
150 #define obstack_chunk_free free
151
152 /* The resource building obstack. */
153
154 static struct obstack res_obstack;
155
156 /* Initialize the resource building obstack. */
157
158 static void
159 res_init ()
160 {
161 obstack_init (&res_obstack);
162 }
163
164 /* Allocate space on the resource building obstack. */
165
166 PTR
167 res_alloc (bytes)
168 size_t bytes;
169 {
170 return (PTR) obstack_alloc (&res_obstack, bytes);
171 }
172
173 /* We also use an obstack to save memory used while writing out a set
174 of resources. */
175
176 static struct obstack reswr_obstack;
177
178 /* Initialize the resource writing obstack. */
179
180 static void
181 reswr_init ()
182 {
183 obstack_init (&reswr_obstack);
184 }
185
186 /* Allocate space on the resource writing obstack. */
187
188 PTR
189 reswr_alloc (bytes)
190 size_t bytes;
191 {
192 return (PTR) obstack_alloc (&reswr_obstack, bytes);
193 }
194 \f
195 /* Open a file using the include directory search list. */
196
197 FILE *
198 open_file_search (filename, mode, errmsg, real_filename)
199 const char *filename;
200 const char *mode;
201 const char *errmsg;
202 char **real_filename;
203 {
204 FILE *e;
205 struct include_dir *d;
206
207 e = fopen (filename, mode);
208 if (e != NULL)
209 {
210 *real_filename = xstrdup (filename);
211 return e;
212 }
213
214 if (errno == ENOENT)
215 {
216 for (d = include_dirs; d != NULL; d = d->next)
217 {
218 char *n;
219
220 n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
221 sprintf (n, "%s/%s", d->dir, filename);
222 e = fopen (n, mode);
223 if (e != NULL)
224 {
225 *real_filename = n;
226 return e;
227 }
228
229 if (errno != ENOENT)
230 break;
231 }
232 }
233
234 fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
235
236 /* Return a value to avoid a compiler warning. */
237 return NULL;
238 }
239 \f
240 /* Compare two resource ID's. We consider name entries to come before
241 numeric entries, because that is how they appear in the COFF .rsrc
242 section. */
243
244 int
245 res_id_cmp (a, b)
246 struct res_id a;
247 struct res_id b;
248 {
249 if (! a.named)
250 {
251 if (b.named)
252 return 1;
253 if (a.u.id > b.u.id)
254 return 1;
255 else if (a.u.id < b.u.id)
256 return -1;
257 else
258 return 0;
259 }
260 else
261 {
262 unichar *as, *ase, *bs, *bse;
263
264 if (! b.named)
265 return -1;
266
267 as = a.u.n.name;
268 ase = as + a.u.n.length;
269 bs = b.u.n.name;
270 bse = bs + b.u.n.length;
271
272 while (as < ase)
273 {
274 int i;
275
276 if (bs >= bse)
277 return 1;
278 i = (int) *as - (int) *bs;
279 if (i != 0)
280 return i;
281 ++as;
282 ++bs;
283 }
284
285 if (bs < bse)
286 return -1;
287
288 return 0;
289 }
290 }
291
292 /* Print a resource ID. */
293
294 void
295 res_id_print (stream, id, quote)
296 FILE *stream;
297 struct res_id id;
298 int quote;
299 {
300 if (! id.named)
301 fprintf (stream, "%lu", id.u.id);
302 else
303 {
304 if (quote)
305 putc ('"', stream);
306 unicode_print (stream, id.u.n.name, id.u.n.length);
307 if (quote)
308 putc ('"', stream);
309 }
310 }
311
312 /* Print a list of resource ID's. */
313
314 void
315 res_ids_print (stream, cids, ids)
316 FILE *stream;
317 int cids;
318 const struct res_id *ids;
319 {
320 int i;
321
322 for (i = 0; i < cids; i++)
323 {
324 res_id_print (stream, ids[i], 1);
325 if (i + 1 < cids)
326 fprintf (stream, ": ");
327 }
328 }
329
330 /* Convert an ASCII string to a resource ID. */
331
332 void
333 res_string_to_id (res_id, string)
334 struct res_id *res_id;
335 const char *string;
336 {
337 res_id->named = 1;
338 unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
339 }
340
341 /* Define a resource. The arguments are the resource tree, RESOURCES,
342 and the location at which to put it in the tree, CIDS and IDS.
343 This returns a newly allocated res_resource structure, which the
344 caller is expected to initialize. If DUPOK is non-zero, then if a
345 resource with this ID exists, it is returned. Otherwise, a warning
346 is issued, and a new resource is created replacing the existing
347 one. */
348
349 struct res_resource *
350 define_resource (resources, cids, ids, dupok)
351 struct res_directory **resources;
352 int cids;
353 const struct res_id *ids;
354 int dupok;
355 {
356 struct res_entry *re = NULL;
357 int i;
358
359 assert (cids > 0);
360 for (i = 0; i < cids; i++)
361 {
362 struct res_entry **pp;
363
364 if (*resources == NULL)
365 {
366 static unsigned long timeval;
367
368 /* Use the same timestamp for every resource created in a
369 single run. */
370 if (timeval == 0)
371 timeval = time (NULL);
372
373 *resources = ((struct res_directory *)
374 res_alloc (sizeof **resources));
375 (*resources)->characteristics = 0;
376 (*resources)->time = timeval;
377 (*resources)->major = 0;
378 (*resources)->minor = 0;
379 (*resources)->entries = NULL;
380 }
381
382 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
383 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
384 break;
385
386 if (*pp != NULL)
387 re = *pp;
388 else
389 {
390 re = (struct res_entry *) res_alloc (sizeof *re);
391 re->next = NULL;
392 re->id = ids[i];
393 if ((i + 1) < cids)
394 {
395 re->subdir = 1;
396 re->u.dir = NULL;
397 }
398 else
399 {
400 re->subdir = 0;
401 re->u.res = NULL;
402 }
403
404 *pp = re;
405 }
406
407 if ((i + 1) < cids)
408 {
409 if (! re->subdir)
410 {
411 fprintf (stderr, "%s: ", program_name);
412 res_ids_print (stderr, i, ids);
413 fprintf (stderr, _(": expected to be a directory\n"));
414 xexit (1);
415 }
416
417 resources = &re->u.dir;
418 }
419 }
420
421 if (re->subdir)
422 {
423 fprintf (stderr, "%s: ", program_name);
424 res_ids_print (stderr, cids, ids);
425 fprintf (stderr, _(": expected to be a leaf\n"));
426 xexit (1);
427 }
428
429 if (re->u.res != NULL)
430 {
431 if (dupok)
432 return re->u.res;
433
434 fprintf (stderr, _("%s: warning: "), program_name);
435 res_ids_print (stderr, cids, ids);
436 fprintf (stderr, _(": duplicate value\n"));
437 }
438
439 re->u.res = ((struct res_resource *)
440 res_alloc (sizeof (struct res_resource)));
441 memset (re->u.res, 0, sizeof (struct res_resource));
442
443 re->u.res->type = RES_TYPE_UNINITIALIZED;
444 return re->u.res;
445 }
446
447 /* Define a standard resource. This is a version of define_resource
448 that just takes type, name, and language arguments. */
449
450 struct res_resource *
451 define_standard_resource (resources, type, name, language, dupok)
452 struct res_directory **resources;
453 int type;
454 struct res_id name;
455 int language;
456 int dupok;
457 {
458 struct res_id a[3];
459
460 a[0].named = 0;
461 a[0].u.id = type;
462 a[1] = name;
463 a[2].named = 0;
464 a[2].u.id = language;
465 return define_resource (resources, 3, a, dupok);
466 }
467
468 /* Comparison routine for resource sorting. */
469
470 static int
471 cmp_res_entry (p1, p2)
472 const PTR p1;
473 const PTR p2;
474 {
475 const struct res_entry **re1, **re2;
476
477 re1 = (const struct res_entry **) p1;
478 re2 = (const struct res_entry **) p2;
479 return res_id_cmp ((*re1)->id, (*re2)->id);
480 }
481
482 /* Sort the resources. */
483
484 static struct res_directory *
485 sort_resources (resdir)
486 struct res_directory *resdir;
487 {
488 int c, i;
489 struct res_entry *re;
490 struct res_entry **a;
491
492 if (resdir->entries == NULL)
493 return resdir;
494
495 c = 0;
496 for (re = resdir->entries; re != NULL; re = re->next)
497 ++c;
498
499 /* This is a recursive routine, so using xmalloc is probably better
500 than alloca. */
501 a = (struct res_entry **) xmalloc (c * sizeof (struct res_entry *));
502
503 for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
504 a[i] = re;
505
506 qsort (a, c, sizeof (struct res_entry *), cmp_res_entry);
507
508 resdir->entries = a[0];
509 for (i = 0; i < c - 1; i++)
510 a[i]->next = a[i + 1];
511 a[i]->next = NULL;
512
513 free (a);
514
515 /* Now sort the subdirectories. */
516
517 for (re = resdir->entries; re != NULL; re = re->next)
518 if (re->subdir)
519 re->u.dir = sort_resources (re->u.dir);
520
521 return resdir;
522 }
523 \f
524 /* Return whether the dialog resource DIALOG is a DIALOG or a
525 DIALOGEX. */
526
527 int
528 extended_dialog (dialog)
529 const struct dialog *dialog;
530 {
531 const struct dialog_control *c;
532
533 if (dialog->ex != NULL)
534 return 1;
535
536 for (c = dialog->controls; c != NULL; c = c->next)
537 if (c->data != NULL || c->help != 0)
538 return 1;
539
540 return 0;
541 }
542
543 /* Return whether MENUITEMS are a MENU or a MENUEX. */
544
545 int
546 extended_menu (menu)
547 const struct menu *menu;
548 {
549 return extended_menuitems (menu->items);
550 }
551
552 static int
553 extended_menuitems (menuitems)
554 const struct menuitem *menuitems;
555 {
556 const struct menuitem *mi;
557
558 for (mi = menuitems; mi != NULL; mi = mi->next)
559 {
560 if (mi->help != 0 || mi->state != 0)
561 return 1;
562 if (mi->popup != NULL && mi->id != 0)
563 return 1;
564 if ((mi->type
565 & ~ (MENUITEM_CHECKED
566 | MENUITEM_GRAYED
567 | MENUITEM_HELP
568 | MENUITEM_INACTIVE
569 | MENUITEM_MENUBARBREAK
570 | MENUITEM_MENUBREAK))
571 != 0)
572 return 1;
573 if (mi->popup != NULL)
574 {
575 if (extended_menuitems (mi->popup))
576 return 1;
577 }
578 }
579
580 return 0;
581 }
582 \f
583 /* Convert a string to a format type, or exit if it can't be done. */
584
585 static enum res_format
586 format_from_name (name)
587 const char *name;
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)
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 -I --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 --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 --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 output_format;
780 char *target;
781 char *preprocessor;
782 char *preprocargs;
783 const char *quotedarg;
784 int language;
785 struct res_directory *resources;
786 int use_temp_file;
787
788 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
789 setlocale (LC_MESSAGES, "");
790 #endif
791 #if defined (HAVE_SETLOCALE)
792 setlocale (LC_CTYPE, "");
793 #endif
794 bindtextdomain (PACKAGE, LOCALEDIR);
795 textdomain (PACKAGE);
796
797 program_name = argv[0];
798 xmalloc_set_program_name (program_name);
799
800 bfd_init ();
801 set_default_bfd_target ();
802
803 res_init ();
804
805 input_filename = NULL;
806 output_filename = NULL;
807 input_format = RES_FORMAT_UNKNOWN;
808 output_format = RES_FORMAT_UNKNOWN;
809 target = NULL;
810 preprocessor = NULL;
811 preprocargs = NULL;
812 language = 0x409; /* LANG_ENGLISH, SUBLANG_ENGLISH_US. */
813 use_temp_file = 0;
814
815 while ((c = getopt_long (argc, argv, "i:l:o:I:O:F:D:U:rhHvV", long_options,
816 (int *) 0)) != EOF)
817 {
818 switch (c)
819 {
820 case 'i':
821 input_filename = optarg;
822 break;
823
824 case 'o':
825 output_filename = optarg;
826 break;
827
828 case 'I':
829 input_format = format_from_name (optarg);
830 break;
831
832 case 'O':
833 output_format = format_from_name (optarg);
834 break;
835
836 case 'F':
837 target = optarg;
838 break;
839
840 case OPTION_PREPROCESSOR:
841 preprocessor = optarg;
842 break;
843
844 case 'D':
845 case 'U':
846 if (preprocargs == NULL)
847 {
848 quotedarg = quot (optarg);
849 preprocargs = xmalloc (strlen (quotedarg) + 3);
850 sprintf (preprocargs, "-%c%s", c, quotedarg);
851 }
852 else
853 {
854 char *n;
855
856 quotedarg = quot (optarg);
857 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
858 sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
859 free (preprocargs);
860 preprocargs = n;
861 }
862 break;
863
864 case 'r':
865 /* Ignored for compatibility with rc. */
866 break;
867
868 case 'v':
869 verbose ++;
870 break;
871
872 case OPTION_INCLUDE_DIR:
873 if (preprocargs == NULL)
874 {
875 quotedarg = quot (optarg);
876 preprocargs = xmalloc (strlen (quotedarg) + 3);
877 sprintf (preprocargs, "-I%s", quotedarg);
878 }
879 else
880 {
881 char *n;
882
883 quotedarg = quot (optarg);
884 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
885 sprintf (n, "%s -I%s", preprocargs, quotedarg);
886 free (preprocargs);
887 preprocargs = n;
888 }
889
890 {
891 struct include_dir *n, **pp;
892
893 n = (struct include_dir *) xmalloc (sizeof *n);
894 n->next = NULL;
895 n->dir = optarg;
896
897 for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
898 ;
899 *pp = n;
900 }
901
902 break;
903
904 case 'l':
905 language = strtol (optarg, (char **) NULL, 16);
906 break;
907
908 case OPTION_USE_TEMP_FILE:
909 use_temp_file = 1;
910 break;
911
912 case OPTION_NO_USE_TEMP_FILE:
913 use_temp_file = 0;
914 break;
915
916 #ifdef YYDEBUG
917 case OPTION_YYDEBUG:
918 yydebug = 1;
919 break;
920 #endif
921
922 case 'h':
923 case 'H':
924 usage (stdout, 0);
925 break;
926
927 case 'V':
928 print_version ("windres");
929 break;
930
931 default:
932 usage (stderr, 1);
933 break;
934 }
935 }
936
937 if (input_filename == NULL && optind < argc)
938 {
939 input_filename = argv[optind];
940 ++optind;
941 }
942
943 if (output_filename == NULL && optind < argc)
944 {
945 output_filename = argv[optind];
946 ++optind;
947 }
948
949 if (argc != optind)
950 usage (stderr, 1);
951
952 if (input_format == RES_FORMAT_UNKNOWN)
953 {
954 if (input_filename == NULL)
955 input_format = RES_FORMAT_RC;
956 else
957 input_format = format_from_filename (input_filename, 1);
958 }
959
960 if (output_format == RES_FORMAT_UNKNOWN)
961 {
962 if (output_filename == NULL)
963 output_format = RES_FORMAT_RC;
964 else
965 output_format = format_from_filename (output_filename, 0);
966 }
967
968 /* Read the input file. */
969 switch (input_format)
970 {
971 default:
972 abort ();
973 case RES_FORMAT_RC:
974 resources = read_rc_file (input_filename, preprocessor, preprocargs,
975 language, use_temp_file);
976 break;
977 case RES_FORMAT_RES:
978 resources = read_res_file (input_filename);
979 break;
980 case RES_FORMAT_COFF:
981 resources = read_coff_rsrc (input_filename, target);
982 break;
983 }
984
985 if (resources == NULL)
986 fatal (_("no resources"));
987
988 /* Sort the resources. This is required for COFF, convenient for
989 rc, and unimportant for res. */
990 resources = sort_resources (resources);
991
992 /* Write the output file. */
993 reswr_init ();
994
995 switch (output_format)
996 {
997 default:
998 abort ();
999 case RES_FORMAT_RC:
1000 write_rc_file (output_filename, resources);
1001 break;
1002 case RES_FORMAT_RES:
1003 write_res_file (output_filename, resources);
1004 break;
1005 case RES_FORMAT_COFF:
1006 write_coff_file (output_filename, target, resources);
1007 break;
1008 }
1009
1010 xexit (0);
1011 return 0;
1012 }
1013
This page took 0.049466 seconds and 4 git commands to generate.