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

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

Initial revision

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