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