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