Mon Nov 9 12:00:36 1998 Dave Brolley <brolley@cygnus.com>
[deliverable/binutils-gdb.git] / binutils / windres.c
CommitLineData
1d371d35 1/* windres.c -- a program to manipulate Windows resources
9d04d618 2 Copyright 1997, 1998 Free Software Foundation, Inc.
1d371d35
ILT
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>
9d04d618 47#include <time.h>
1d371d35
ILT
48
49/* An enumeration of format types. */
50
51enum 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
65struct format_map
66{
67 const char *name;
68 enum res_format format;
69};
70
71/* A mapping between names and format types. */
72
73static 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
83static 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
95struct include_dir
96{
97 struct include_dir *next;
98 char *dir;
99};
100
101static 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
115static 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
662cc41e
ILT
132static void res_init PARAMS ((void));
133static int extended_menuitems PARAMS ((const struct menuitem *));
1d371d35
ILT
134static enum res_format format_from_name PARAMS ((const char *));
135static enum res_format format_from_filename PARAMS ((const char *, int));
136static void usage PARAMS ((FILE *, int));
662cc41e
ILT
137static int cmp_res_entry PARAMS ((const PTR, const PTR));
138static 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
148static struct obstack res_obstack;
149
150/* Initialize the resource building obstack. */
151
152static void
153res_init ()
154{
155 obstack_init (&res_obstack);
156}
157
158/* Allocate space on the resource building obstack. */
159
160PTR
161res_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
170static struct obstack reswr_obstack;
171
172/* Initialize the resource writing obstack. */
173
174static void
175reswr_init ()
176{
177 obstack_init (&reswr_obstack);
178}
179
180/* Allocate space on the resource writing obstack. */
181
182PTR
183reswr_alloc (bytes)
184 size_t bytes;
185{
186 return (PTR) obstack_alloc (&reswr_obstack, bytes);
187}
1d371d35
ILT
188\f
189/* Open a file using the include directory search list. */
190
191FILE *
192open_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
9d04d618 228 fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
1d371d35
ILT
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
239void
240unicode_from_ascii (length, unicode, ascii)
662cc41e
ILT
241 int *length;
242 unichar **unicode;
1d371d35
ILT
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)
662cc41e 252 *length = len;
1d371d35 253
662cc41e 254 *unicode = ((unichar *) res_alloc ((len + 1) * sizeof (unichar)));
1d371d35
ILT
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
265void
266unicode_print (e, unicode, length)
267 FILE *e;
662cc41e 268 const unichar *unicode;
1d371d35
ILT
269 int length;
270{
271 while (1)
272 {
662cc41e 273 unichar ch;
1d371d35
ILT
274
275 if (length == 0)
276 return;
277 if (length > 0)
278 --length;
279
280 ch = *unicode;
281
662cc41e 282 if (ch == 0 && length < 0)
1d371d35
ILT
283 return;
284
285 ++unicode;
286
9d04d618
TT
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 }
1d371d35
ILT
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
342int
343res_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 {
662cc41e 360 unichar *as, *ase, *bs, *bse;
1d371d35
ILT
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
392void
393res_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 {
1d371d35
ILT
402 if (quote)
403 putc ('"', stream);
e4486bdf 404 unicode_print (stream, id.u.n.name, id.u.n.length);
1d371d35
ILT
405 if (quote)
406 putc ('"', stream);
407 }
408}
409
410/* Print a list of resource ID's. */
411
412void
413res_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
430void
431res_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
447struct res_resource *
448define_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 {
9d04d618
TT
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
662cc41e
ILT
471 *resources = ((struct res_directory *)
472 res_alloc (sizeof **resources));
1d371d35 473 (*resources)->characteristics = 0;
9d04d618 474 (*resources)->time = timeval;
1d371d35
ILT
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 {
662cc41e 488 re = (struct res_entry *) res_alloc (sizeof *re);
1d371d35
ILT
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);
9d04d618 511 fprintf (stderr, _(": expected to be a directory\n"));
1d371d35
ILT
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);
9d04d618 523 fprintf (stderr, _(": expected to be a leaf\n"));
1d371d35
ILT
524 xexit (1);
525 }
526
527 if (re->u.res != NULL)
528 {
529 if (dupok)
530 return re->u.res;
531
9d04d618 532 fprintf (stderr, _("%s: warning: "), program_name);
1d371d35 533 res_ids_print (stderr, cids, ids);
9d04d618 534 fprintf (stderr, _(": duplicate value\n"));
1d371d35
ILT
535 }
536
662cc41e
ILT
537 re->u.res = ((struct res_resource *)
538 res_alloc (sizeof (struct res_resource)));
1d371d35
ILT
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
550struct res_resource *
551define_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}
662cc41e
ILT
567
568/* Comparison routine for resource sorting. */
569
570static int
571cmp_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
584static struct res_directory *
585sort_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}
1d371d35
ILT
623\f
624/* Return whether the dialog resource DIALOG is a DIALOG or a
625 DIALOGEX. */
626
627int
628extended_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
645int
662cc41e
ILT
646extended_menu (menu)
647 const struct menu *menu;
648{
649 return extended_menuitems (menu->items);
650}
651
652static int
653extended_menuitems (menuitems)
1d371d35
ILT
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 {
662cc41e 675 if (extended_menuitems (mi->popup))
1d371d35
ILT
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
685static enum res_format
686format_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 {
9d04d618
TT
697 fprintf (stderr, _("%s: unknown format type `%s'\n"), program_name, name);
698 fprintf (stderr, _("%s: supported formats:"), program_name);
1d371d35
ILT
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
711static enum res_format
712format_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
e4486bdf
ILT
755 /* A PE executable starts with 0x4d 0x5a. */
756 if (b1 == 0x4d && b2 == 0x5a)
1d371d35
ILT
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. */
9d04d618 785 fatal (_("can not determine type of file `%s'; use the -I option"),
1d371d35
ILT
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
794static void
795usage (stream, status)
796 FILE *stream;
797 int status;
798{
9d04d618 799 fprintf (stream, _("Usage: %s [options] [input-file] [output-file]\n"),
1d371d35 800 program_name);
9d04d618 801 fprintf (stream, _("\
1d371d35
ILT
802Options:\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\
9d04d618 813 --language VAL Set language when reading rc file\n"));
1d371d35 814#ifdef YYDEBUG
9d04d618
TT
815 fprintf (stream, _("\
816 --yydebug Turn on parser debugging\n"));
1d371d35 817#endif
9d04d618 818 fprintf (stream, _("\
1d371d35 819 --help Print this help message\n\
9d04d618
TT
820 --version Print version information\n"));
821 fprintf (stream, _("\
1d371d35
ILT
822FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
823extension if not specified. A single file name is an input file.\n\
9d04d618 824No input-file is stdin, default rc. No output-file is stdout, default rc.\n"));
1d371d35
ILT
825 list_supported_targets (program_name, stream);
826 if (status == 0)
9d04d618 827 fprintf (stream, _("Report bugs to bug-gnu-utils@gnu.org\n"));
1d371d35
ILT
828 exit (status);
829}
830
831/* The main function. */
832
833int
834main (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
19ac4b08
TT
849 setlocale (LC_MESSAGES, "");
850 bindtextdomain (PACKAGE, LOCALEDIR);
851 textdomain (PACKAGE);
852
1d371d35
ILT
853 program_name = argv[0];
854 xmalloc_set_program_name (program_name);
855
856 bfd_init ();
857 set_default_bfd_target ();
858
662cc41e
ILT
859 res_init ();
860
1d371d35
ILT
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
d5a7bb53 1019 if (resources == NULL)
9d04d618 1020 fatal (_("no resources"));
d5a7bb53 1021
662cc41e
ILT
1022 /* Sort the resources. This is required for COFF, convenient for
1023 rc, and unimportant for res. */
1024
1025 resources = sort_resources (resources);
1026
1d371d35
ILT
1027 /* Write the output file. */
1028
662cc41e
ILT
1029 reswr_init ();
1030
1d371d35
ILT
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
1050struct res_directory *
1051read_res_file (filename)
1052 const char *filename;
1053{
9d04d618 1054 fatal (_("read_res_file unimplemented"));
1d371d35
ILT
1055 return NULL;
1056}
1057
1d371d35
ILT
1058void
1059write_res_file (filename, resources)
1060 const char *filename;
1061 const struct res_directory *resources;
1062{
9d04d618 1063 fatal (_("write_res_file unimplemented"));
1d371d35 1064}
This page took 0.097629 seconds and 4 git commands to generate.