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